纯TypeScript实现AI图片签名与标记
Filigrane是MIT许可的TypeScript工具包,面向浏览器和边缘运行时,基于WebCrypto实现所需的C2PA相关结构与签名。文章具体解释了清单大小与哈希排除范围相互依赖的问题,以及通过迭代稳定文件布局的处理方法。
AI 深度解读
给 AI 图片加一个「AI 生成」标签,转存一次就可能丢掉。Filigrane 的作者想解决的是:图片经过平台重编码后,还能不能识别它来自 AI?他的方案是用纯 TypeScript 组合签名凭证、行业元数据和像素水印,让不同标记互相补位。
这篇最值得程序员读的,是浏览器里的实现取舍,以及作者如何攻击自己的验证器。至于这些能力是否足以满足欧盟法规,需要和工程测试分开判断。
为什么图片需要三种标记
按作者的描述,EU AI Act 自 2026 年 8 月 2 日起要求 AI 产品为生成内容添加机器可读标记,欧盟委员会的 Code of Practice 建议至少采用两层,已上市系统的期限是 12 月 2 日。这些是原文给出的法规背景,文章没有展开适用范围与例外,不能直接作为具体产品的合规结论。
Filigrane 实际做了三层。
第一层是 C2PA,也叫 Content Credentials。它把带签名的声明清单嵌入文件,用来检查文件内容与签名声明是否对应。官方 SDK 使用 Rust,npm 包带原生二进制;作者为了支持浏览器和边缘运行时,用 TypeScript 与 WebCrypto 实现了所需的 CBOR 编解码、JUMBF 容器、COSE_Sign1 签名和 X.509 证书处理。
这里有个循环依赖:清单要记录排除自身后的文件哈希,但排除范围取决于清单大小,清单大小又受范围编码影响。作者通过「构建、测量、重建」的固定点循环稳定布局,称两次迭代就能收敛。
第二层是 IPTC 元数据。它在 XMP 中写入 DigitalSourceType 字段,值为 trainedAlgorithmicMedia,供搜索引擎和图片工具识别 AI 来源。它解决的是现有工具如何读懂标记,不能替代签名校验。
第三层是不可见水印。社交平台重新编码图片时,元数据可能消失,因此作者把 64-bit 编码分散到图片标准化后的 256 像素副本的数千个 DCT(离散余弦变换)系数中。可以把它理解为:把标记藏进图像信号,而不只写在文件附带的信息里。
三层方案的价值,是让不同标记覆盖不同的失效方式。
水印 ID 还会作为 soft binding(软绑定)写入 C2PA 清单,让像素中的标记和签名声明建立关联。
浏览器能跑,离可靠交付还差哪些验证
作者称,C2PA、密码学、JPEG/PNG 编解码和水印组成的引擎 gzip 后约 33 kB,运行在 Web Worker 中;在线验证器不上传文件。对前端来说,这提供了一条本地处理路径。
水印采用按需调整系数的嵌入方式,在平坦区域改得更少,报告的 PSNR 约为 44 dB。作者在 5 张类照片图片上测试,称水印能经受 JPEG quality 30、缩小至 25%、亮度和对比度变化,以及元数据移除;另在 20 张未标记图片上没有出现误报。
但它目前扛不住裁剪。文章也没有给出截图、插画等图片类型的结果,不能把这组测试推广到所有生成图片。
签名部分的验证更有借鉴意义:每次提交,CI 都会对 JPEG、PNG、WebP 签名,再通过 Python bindings 调用参考实现 c2pa-rs 验证,报告结果均为「Valid」。这样能减少实现与自家验证器同时犯错的风险。
作者还主动攻击验证器,发现过几类严重问题:未签名的 assertion 能让被完全修改的图片显示有效;非 CA 证书能签发被错误信任的证书;特制 PNG 能卡住解析器;500 kB PNG 能膨胀为 512 MB 内存占用。
据作者描述,这些问题已在 0.1.2 修复,每个攻击都加入回归测试,另有 fuzzer 跑过 3,000 个损坏文件而未挂起。这些结果说明防护有所加强,不能证明解析器已经没有漏洞。
下面是原文给出的安装与扫描入口:
npm install @filigranejs/core @filigranejs/ui
npx filigrane scan .
要留意第二行:文章没有解释 scan 的检查范围,因此不能把执行成功理解为项目已满足全部要求。
此外,作者为 Article 50 所述的 AI 交互告知要求提供了 <ai-disclosure> Web Component,支持欧盟 24 种官方语言,可用于不同框架,关闭后仍保留可见的「AI」标记。它处理的是用户告知,与图片来源标记属于不同问题。
我的判断
我认同作者把多层标记与交叉验证放在一起做。仅有 IPTC 信息,难以抵抗重编码;仅有水印,又缺少完整的签名声明。三层组合的工程理由成立。
但水印效果目前只能算小样本实测。5 张测试图和 20 张阴性样本,不足以说明复杂分发链路中的检出率与误报率。约 44 dB PSNR 也是失真指标,不能单独证明所有图片上都看不见改动。
纯 TypeScript 有利于浏览器和边缘部署,但作者明确只实现了自己需要的 C2PA 部分,不能据此认为它与官方 SDK 功能等价。原文也没有提供与官方 SDK、其他水印算法的对照数据,体积与兼容性优势需要按项目继续验证。
还应分清「签名验证通过」「证书受信任」「图片内容真实」三个判断。作者发现的漏洞恰好说明,验证界面上的一个「有效」,背后可能有多条需要分别检查的信任条件。
能拿来做什么
- 如果你正在做 AI 图片生成或导出功能,可以把 C2PA、IPTC 与水印作为三项能力评估,并用真实分发平台处理后的文件测试标记是否保留。
- 如果你准备在前端接入,先拿照片、插画、截图等业务素材验证视觉变化、处理耗时和检出情况,尤其要单独测试裁剪。
- 如果你维护文件解析器或使用 AI 编程助手生成底层代码,可以借鉴作者的方法:用参考实现交叉验证,把攻击样本保留为回归测试,再用模糊测试寻找异常输入。
- 如果你需要 AI 交互告知组件,可以评估
<ai-disclosure>的展示与关闭行为,同时单独核对产品适用的告知要求。