---
title: 如何核查内容凭证，以及它不能说明什么
dek: 发布或引用一张图片、一段视频之前，用这份六步核查表判断它的 C2PA 清单能确立什么：谁签署了哪些声明，这些声明又覆盖哪些字节。
needs: 收到时原样的文件、C2PA 验证器和 C2PA 信任列表
---

通过验证的内容凭证（Content Credentials）能说明，哪个证书持有者签署了关于某个文件的一组声明，以及这些声明覆盖文件的哪些字节。声明是否属实，仍要由依赖这些声明的人判断。[^1]内容凭证是一种清单（manifest），规范由内容来源与真实性联盟（C2PA）制定。清单中关于资产的陈述称为断言（assertion）；这些断言列在一份声明（claim）中，由签名者签署。[^1]如果你要依据凭证发布、引用或标注一张图片或一段视频，请先完成下面六项检查。

## 需要准备什么

- **验证器**，例如 c2patool。这是一款开源命令行工具，内容真实性倡议（CAI）为它提供了使用文档。[^2]据 CAI 的文档介绍，verify.contentauthenticity.org 上的 Verify 工具对照一份旧版临时信任列表检查签名者，而不是对照 C2PA 信任列表。[^2, 3]
- **文件本身**，保持收到时的原样，连同可能附带的单独 `.c2pa` 清单文件；c2patool 用 `--external-manifest` 读取这类文件。[^2]重新编码或调整过尺寸的副本，无法与清单的硬绑定相符。硬绑定是根据原始资产的字节计算出的密码学哈希。[^1]
- **C2PA 信任列表。**其中一份列出的证书颁发机构（CA）向符合规范的产品颁发签名证书。另一份列出的 CA 为时间戳机构（TSA）颁发证书。两份列表都存放在 C2PA 在 GitHub 上的 conformance-public 仓库中。[^3]

## 第 1 步：确认清单存在并通过验证

规范为清单定义了三种状态，每一种都以前一种为前提：[^1]

| 状态 | 验证已确认的内容 |
| --- | --- |
| 格式正确（Well-formed） | 清单及其断言符合规范的要求 |
| 有效（Valid） | 签名验证通过；证书处于有效期内，且未被报告为已吊销 |
| 可信（Trusted） | 证书还能沿证书链追溯到信任锚，即验证器接受的 CA 证书；或者用户已把这张证书加入验证器的私有凭证库 |

只有哈希覆盖的字节也没有改变，资产才算有效。如果清单有效，你可以把其中的声明归属于声明生成器（claim generator），即 `claim_generator_info` 中列出的硬件或软件。[^1]在 c2patool 中，`--info` 报告清单是否通过验证，不加选项的命令则输出清单数据。[^2]

```bash
c2patool image.jpg --info
c2patool image.jpg
```

- [ ] 声明签名通过验证（`claimSignature.validated`）
- [ ] 硬绑定与文件相符，例如 `assertion.dataHash.match`
- [ ] 记下声明生成器和出现的任何失败代码

## 第 2 步：确定签名者，并对照 C2PA 信任列表检查

先找出签名者，即签名证书的持有者，由证书的主体（subject）标识。[^1]在 C2PA 符合性计划（Conformance Program）中，签名者总是某个生成类产品的一个实例；生成类产品指生成资产并为其附上清单的系统。C2PA 信任列表上的 CA 只能向符合规范的产品颁发签名证书。[^4]每张证书都写明产品名称，并记录一个保障等级（目前为 1 级或 2 级），反映该产品满足了哪些安全要求。[^4]因此，如果凭证对照这份列表判定为可信，它指明的是一个产品，例如一款相机应用。

`--certs` 选项输出证书链，`trust` 子命令则对照 `--trust_anchors` 传入的列表检查证书链。[^2]如果证书链追溯不到验证器接受的任何信任锚，验证器会报告 `signingCredential.untrusted`。[^1]

```bash
c2patool image.jpg --certs
c2patool image.jpg trust --trust_anchors='https://raw.githubusercontent.com/c2pa-org/conformance-public/refs/heads/main/trust-list/C2PA-TRUST-LIST.pem'
```

符合性计划和符合规范的验证器都存在有据可查的缺陷。2026 年 4 月，马里兰大学巴尔的摩县分校（UMBC）研究人员牵头发表了一项安全分析，称该计划 0.1 版不经技术审查就认证产品。[^6]自 2026 年 10 月 9 日起，0.2 版成为唯一接受申请的版本。它要求提交样本输出文件，每条记录还须经第二名审批人批准。[^4] UMBC 牵头的作者团队还发现，Nikon 于 2025 年 11 月吊销一台相机的证书后，有两个符合规范的验证器没有报告这次吊销。[^7]按照规范，在线验证器应当尝试检查吊销状态。[^1]

- [ ] 记下证书的主体、颁发者、有效期和保障等级
- [ ] 对照 C2PA 信任列表检查证书链，并注明获取列表的时间
- [ ] 记下验证器是否检查了吊销状态

## 第 3 步：把签名者的断言与其他数据区分开

先给验证器显示的内容分类，因为其中只有一部分归属于签名者。创建型断言（created assertion）归属于签名者。收集型断言（gathered assertion）来自工作流程的其他环节，例如有人手动输入的细节。这类断言作为声明的一部分一同签名，但不归属于签名者。[^1]清单以外的元数据，例如可交换图像文件格式（EXIF）字段，即使在哈希覆盖范围内，也不归属于签名者。只有复制到创建型断言中的 `c2pa.metadata` 断言里，这些元数据才归属于签名者。[^1]

操作断言（actions assertion）列明对资产做过哪些操作。新资产的第一个操作是 `c2pa.created`，并带有数字来源类型（digital source type），例如生成式 AI 模型的输出标为 `trainedAlgorithmicMedia`。经过编辑的资产，第一个操作是 `c2pa.opened`，并有一条成分断言（ingredient assertion）描述原始资产。[^1]规范 2.4 版新增了 `c2pa.ai-disclosure` 断言，用于记录模型类型等细节。[^1]除非 `allActionsIncluded` 为 true，否则可能还有其他操作没有记录在内。[^1]

- [ ] 列出创建型断言，包括每个操作及其数字来源类型
- [ ] 把收集型断言单独列出，注明它们不归属于签名者
- [ ] 把显示出来的清单外元数据（例如位置）标为未签名
- [ ] 记下每个成分所带清单的验证结果

## 第 4 步：找出哈希没有覆盖的字节

哈希匹配只能保护它覆盖的字节，因此要列出排除范围（exclusion range），即哈希没有覆盖的字节区间。其中一个排除范围存放清单；除此之外，规范只允许把排除范围用于资产元数据。声明生成器必须确保，攻击者无论在这些区间写入什么，都不能实质性地改变对资产的解读。[^1]如果存放清单的区间里还有其他数据，验证器必须拒绝该清单。遇到额外的排除范围，验证器必须用信息类代码标出，例如 `assertion.dataHash.additionalExclusionsPresent`。[^1]

UMBC 牵头的作者团队报告，一部 Pixel 10 Pro 把位置数据存放在一个排除范围内。他们还报告，自己改动了这些数据，一个符合规范的验证器却没有发现。[^7]安全研究人员 David Buchanan 于 2026 年 10 月 2 日发布了一张图片，图片中只有一个排除范围，覆盖了整个文件。他说，图片的签名有效，却保护不了文件的任何部分，而且他能找到的验证工具都没有对这张图片发出提示。他还用 c2patool 的详细报告展示了这个排除范围。[^2, 5]

```bash
c2patool image.jpg -d
```

- [ ] 列出硬绑定断言（`c2pa.hash.data`、`c2pa.hash.boxes` 或 `c2pa.hash.bmff.v3`）中的排除范围
- [ ] 把每个排除范围与文件大小比较；覆盖整个文件的排除范围什么都保护不了
- [ ] 查明每个额外排除范围存放了什么，并把这些内容视为不受保护

## 第 5 步：对照 TSA 信任列表检查时间戳

查找 TSA 时间戳，它是清单可信时间的唯一来源。TSA 在声明签名之上再加一层签名，表明该签名在时间戳载明的时间已经存在。声明生成器写入的时间，例如某个操作的 `when` 字段，都不可信。[^1]验证器必须能把 TSA 的证书沿证书链追溯到自己的 TSA 信任锚，其中包括 C2PA 的 TSA 信任列表。如果做不到，验证器会报告 `timeStamp.untrusted`，并忽略这个时间戳。[^1]

有了可信时间戳，验证器会按时间戳载明的时间判断证书是否有效。因此，即使证书后来过期或被吊销，凭证仍能通过验证。[^1, 3]没有可信时间戳的话，即使文件没有改动，证书一过期，验证也会失败。[^1, 7]

即使是可信时间戳，也只能说明签名的时间。Buchanan 称，彩票开奖之后，他把中奖号码编辑进了自己的图片。据他介绍，图片附带的可信时间戳比开奖早几个小时，却依然有效，因为签名没有覆盖图片的任何部分。[^5] UMBC 牵头的作者团队补充说，签名数据中没有任何内容指向时间戳，因此时间戳可以被移除和替换，而不会被发现。[^7]

- [ ] 确认结果中有 `timeStamp.trusted`，并记下时间戳载明的时间
- [ ] 检查验证器的 TSA 信任锚是否包括 C2PA 的 TSA 信任列表
- [ ] 如果没有可信时间戳，记下证书的到期日期
- [ ] 把时间戳载明的时间理解为：签名最迟在此时已经存在

## 第 6 步：没有凭证时，查找软绑定和数字水印

不要把缺少清单当作关于文件来源的证据，因为元数据可能被有意或无意地删除。[^9]通过软绑定可以追溯到清单。软绑定是一种标识符，要么根据内容计算得出（例如指纹），要么以不可见的数字水印形式嵌入内容。因此，即使副本的字节与原件不同，软绑定也能与之匹配。[^1]

如果原始清单记录了软绑定，而清单的副本存放在某个清单存储库中，软绑定就能找到这份副本。随后，匹配方必须确认，找回的清单中每个软绑定都与检索时使用的软绑定相符。[^1] CAI 还加上了一道指纹检查，确认内容与找回的清单相符。它指出，水印可能被去除或伪造，指纹匹配也从来不是确定无疑的。[^9]

水印检测工具只能覆盖嵌入了其水印的生成工具。Google 于 2026 年 10 月 7 日向所有人开放 SynthID Detector。Google 称，这款工具可以检查图像、视频或音频文件是否由 Google 或其合作伙伴的 AI 制作，合作伙伴包括 OpenAI、NVIDIA 和 Kakao。[^10]因此，未检出水印的结果说明不了其他生成工具的任何情况，我们[关于这款检测工具的简报](/articles/google-synthid-detector-public/)也指出了这一点。

- [ ] 向消息来源索要原始文件，并按第 1 至 5 步验证找回的任何清单
- [ ] 记下每个检测工具的结果，以及该工具标明的覆盖范围
- [ ] 不要把缺少凭证或未检出水印的检测结果当作正面或反面的证据

## 示例

:::example 示例（假设情形）：一张街道被淹的照片
一家新闻编辑部收到读者发来的一张照片，据称拍的是当天早上街道被淹的情景。一位编辑用 c2patool 和 C2PA 信任列表检查了这张照片：

```text
简化汇总，名称和数值均为虚构。

Signer          ExampleCam 6.1; issuing CA on the C2PA trust list
First action    c2pa.created, digitalCapture
Hard binding    c2pa.hash.data, two exclusion ranges
Success         claimSignature.validated, signingCredential.trusted,
                timeStamp.trusted (08:12), assertion.dataHash.match
Informational   assertion.dataHash.additionalExclusionsPresent
```

哈希覆盖的字节没有改变。签名者是这款相机应用，它的证书说明不了当时是谁拿着手机。第二个排除范围覆盖 EXIF 数据块，因此编辑部软件中显示的位置和拍摄时间既不在哈希范围内，也不归属于签名者。

这份凭证只支持一个结论：某个 ExampleCam 实例最迟在 08:12 为这些像素签署了一份拍摄声明。发布之前，编辑部向读者核实拍摄地点，并与这条街道的独立图像比对。
:::

:::limits 有效的凭证不能说明什么
- 规范的信任模型涵盖签名者的身份，而把所签声明是否属实留给依赖这些声明的人判断。[^1]
- 持有有效证书的签名者也可以签署虚假声明。2026 年 8 月，Buchanan 报告称，他利用一部 Pixel 手机的 root 权限，让 Pixel Camera 应用中受硬件保护的密钥为一张 AI 生成的图片签名，将其标为未经编辑的照片。[^8]
- UMBC 牵头的作者团队发现，符合规范的验证器对同一文件可能得出不同结论，因此要记下你使用的验证器和信任列表。[^7]
:::
