# 证书透明度（CT）详解：日志、SCT 与证书监控

> 证书透明度如何把每张公网 TLS 证书写进公开日志，SCT 是什么，Chrome、Safari、Firefox 各有什么要求，以及怎样监控自己域名的证书。

Source: https://ssl.sh/zh/learn/certificate-transparency/
Last updated: 2026-11-10

证书透明度（Certificate Transparency，CT）要求 CA 把每一张公网可信 TLS 证书提交到只能追加的公开日志，否则浏览器不接受这张证书。日志会返回一个带签名的承诺，叫签名证书时间戳（SCT），浏览器在握手时检查它；任何人都可以在日志里搜索自己域名被签发过哪些证书。截至 2026 年 11 月，Chrome、Safari 和 Firefox 都对公网证书强制执行 CT。

## 为什么需要证书透明度

浏览器信任的 CA 有很多家，任何一家都能给任何域名签发证书，而在 CT 出现之前，这种签发未必有人知道。2011 年，攻击者入侵荷兰 CA DigiNotar，签发了数百张伪造证书，其中一张 `*.google.com` 被用来在伊朗监听用户。同一年，还有攻击者通过 Comodo 一个被盗用的代理商账户拿到了多个大型网站的证书。两起事件里，伪造证书都是很晚才被偶然发现的。

Google 的工程师设计 CT，就是要把“偶然发现”变成“必然发现”。协议于 2013 年 6 月发布为 RFC 6962，很快证明了价值：2015 年，CT 日志暴露出 Symantec 未经授权为 Google 域名签发了证书，这是此后一系列事件中的第一起，最终导致各大浏览器不再信任 Symantec 的根证书。

CT 并不能阻止 CA 签发错误的证书，它保证的是这张证书一定会公开，让域名所有者、浏览器厂商和研究者看得到、来得及处理。

## CT 日志如何工作

CT 日志是一份公开的、只能追加的证书列表，按 Merkle 树组织，任何人都能低成本地验证条目只增不删。每张证书被哈希成一个叶子，两两哈希向上合并，最顶端的那个哈希值就“锁定”了整个日志的内容。日志对这个值签名，称为签名树头（STH）。

```text
                    根哈希（签名后即 STH）
                   /                      \
            h(0x01 | A | B)          h(0x01 | C | D)
              /        \               /        \
      A=h(0x00|e0)  B=h(0x00|e1)  C=h(0x00|e2)  D=h(0x00|e3)
          证书 0       证书 1        证书 2        证书 3
```

两种证明让日志无法作弊：

- **包含证明**：证明某张证书在树里。只需要约 log2(n) 个哈希值，一个有十亿条记录的日志大约 30 个哈希就够了。
- **一致性证明**：证明新的树头包含了旧树头的全部内容，也就是日志没有改写历史。

日志承诺在最大合并延迟（MMD）内把提交的证书并入树中。监控者下载日志，查找自己关心的证书；审计者检查各种证明。

### 分片日志与 static-ct-api

日志运营方正在从 RFC 6962 原来的 HTTP 接口迁移到 static-ct-api：日志以静态、可缓存的 Merkle 树“瓦片”（tile）形式发布，运营成本更低，也更容易镜像。截至 2026 年 11 月，Chrome 的 CT 日志政策要求新申请的日志实现 static-ct-api v1.1.0，2027 年 1 月 1 日之前申请的日志仍可选择 RFC 6962，并把 static-ct-api 日志的 MMD 上限定为 1 分钟。Let's Encrypt 目前只运营基于自家 Sunlight 软件的 static-ct-api 日志（Sycamore 和 Willow），原来的 RFC 6962 日志已经退役。

现在的日志还按时间分片：每个分片（比如以 2026 年下半年命名的那个）只接收到期时间落在对应区间内的证书。分片里的证书全部过期后，这个分片就可以冻结并最终下线。

截至 2026 年 11 月，Chrome 的日志列表里有十余家运营方，包括 Google、Cloudflare、DigiCert、Sectigo、Let's Encrypt，以及国内的 TrustAsia（亚洲诚信）。

## 预证书与 SCT

CA 在签发正式证书之前先把一张“预证书”提交给日志，这样才能把日志的承诺嵌进正式证书。预证书的内容与正式证书完全一致，只多了一个关键的“毒药”扩展（OID 1.3.6.1.4.1.11129.2.4.3），让它无法用于 TLS。

```text
 CA                                         CT 日志（至少 2 家运营方）
  |  1. 提交预证书（含毒药扩展） --------------->|
  |  2. 每个日志返回 SCT  <-----------------------|  “我会在 MMD 内记录它”
  |  3. 签发正式证书，写入 SCT 列表扩展
  |     （1.3.6.1.4.1.11129.2.4.2）
  v
 Web 服务器 --- TLS 握手：证书 + 内嵌 SCT ---> 浏览器
                                    校验 SCT 签名和 CT 政策
```

SCT 里有日志 ID、时间戳和日志对证书数据的签名。它是承诺，不是包含证明：日志保证在 MMD 内记录这条数据，整个生态再去检查它是否真的做到了。CA/B 论坛把已记录的预证书视为 CA 打算签发对应证书的证据，所以预证书签错了同样算错误签发。

用 OpenSSL 就能看到内嵌的 SCT。下面是 2026 年 11 月 letsencrypt.org 网站证书的输出（签名部分已省略）：

```bash
echo | openssl s_client -connect letsencrypt.org:443 -servername letsencrypt.org 2>/dev/null \
  | openssl x509 -noout -issuer -dates -ext ct_precert_scts
```

```text
issuer=C=US, O=Let's Encrypt, CN=YE2
notBefore=Nov  3 13:44:34 2026 GMT
notAfter=Feb  1 13:44:33 2027 GMT
CT Precertificate SCTs:
    Signed Certificate Timestamp:
        Version   : v1 (0x0)
        Log ID    : 4C:63:DC:98:E5:9C:1D:AB:88:F6:1E:8A:3D:DE:AE:8F:
                    AB:44:A3:37:7B:5F:9B:94:C3:FB:A1:9C:FC:C1:BE:26
        Timestamp : Nov  3 14:43:04.256 2026 GMT
        Signature : ecdsa-with-SHA256 ...
    Signed Certificate Timestamp:
        Version   : v1 (0x0)
        Log ID    : 46:A2:39:67:C6:0D:B6:46:87:C6:6F:3D:F9:99:94:76:
                    93:A6:A6:11:20:84:57:D5:55:E7:E3:D0:A1:D9:B6:46
        Timestamp : Nov  3 14:43:06.252 2026 GMT
        Signature : ecdsa-with-SHA256 ...
```

这张证书有效期 90 天，按 Chrome 政策需要来自两个不同日志、两个不同运营方的 SCT，它带的正好是两个。

## SCT 的三种交付方式

SCT 有三种途径到达浏览器，但实际上几乎所有证书都用第一种。

| 方式 | 原理 | 服务器要改什么 | 截至 2026 年 11 月的状况 |
|---|---|---|---|
| 内嵌在证书里 | CA 把 SCT 列表扩展写进正式证书 | 不用改 | 主流方式 |
| TLS 扩展 | 服务器在 `signed_certificate_timestamp` 扩展里发送 SCT | 服务器要自己获取并配置 SCT | 支持，但很少用 |
| OCSP 装订响应 | SCT 放在 OCSP 响应的扩展里 | 需要开启 OCSP 装订 | Chrome 只在 148 之前的版本接受；包括 Let's Encrypt 在内的多家 CA 已不再提供 OCSP |

## 各浏览器的要求

三大浏览器内核现在都会拒绝 SCT 不足的公网证书，具体规则各不相同。下表数字取自截至 2026 年 11 月的官方政策：

| 浏览器 | 对内嵌 SCT 的要求 | 何时开始强制 |
|---|---|---|
| Chrome（及基于 Chromium 的浏览器） | 有效期不超过 180 天需来自 2 个不同日志的 SCT，更长需 3 个；至少一个日志当前仍处于 Qualified、Usable 或 ReadOnly 状态；至少来自两个不同的日志运营方 | 2018 年 4 月 30 日之后签发的证书 |
| Apple 平台（Safari 及使用系统 TLS 的 App） | 180 天以内 2 个，181～398 天 3 个，同一运营方计入的数量有上限；至少一个 SCT 来自 RFC 6962 日志 | 2018 年下半年起 |
| Firefox | Mozilla 根证书计划内 CA 签发的所有证书都必须记录到 CT 日志 | 桌面版 135、安卓版 145 起 |

通过 TLS 扩展发送 SCT 时，Chrome 要求至少两个来自当前受认可日志、分属两个不同运营方的 SCT。另外，如果 Chrome 本地的日志列表超过 70 天没有更新，它会暂停执行 CT，避免长期不更新的浏览器在日志变动时大面积报错。

基于 Chromium 的国产浏览器（360、QQ 浏览器等）是否、以及从哪个版本开始执行 CT，取决于各自跟进的 Chromium 版本和自身改动，排查问题时以实测为准。

有效期缩短也会影响这些规则。2026 年 3 月 15 日起证书最长 200 天，所以有效期 181～200 天的证书在 Chrome 里仍需要 3 个 SCT；2027 年 3 月 15 日上限降到 100 天以后，所有新签发的公网证书都只落在“2 个 SCT”这一档。见 [47 天证书](https://ssl.sh/zh/learn/47-day-certificates/)。

证书不满足政策时，Chrome 会显示 `NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED`。链到用户或企业自行安装的根证书的证书不要求 CT，所以 [私有 CA](https://ssl.sh/zh/cookbook/private-ca/) 签发的内网证书不用进日志。

## 监控自己域名的证书

CT 只有在有人看的时候才起作用，最省事的监控就是定期在日志里搜索自己的域名。crt.sh 这类基于 CT 数据的搜索服务会按名称索引所有已记录的证书，用 `%` 作通配符可以把子域名也查出来：

```bash
curl -s "https://crt.sh/?q=%25.example.com&output=json" \
  | jq -r '.[] | [.not_before, .issuer_name, .name_value] | @tsv' | sort -r | head
```

本站的 [CT 证书搜索](https://ssl.sh/zh/tools/ct-search/) 在浏览器里做同样的查询。查看结果时重点关注：

- **你没用过的 CA。** 如果某张证书来自你从未下过单的 CA，要查清原因。[CAA 记录](https://ssl.sh/zh/learn/caa-records/)可以事先限定哪些 CA 能为你的域名签发，CT 则告诉你这个限制有没有被遵守。注意在阿里云、腾讯云等平台购买的证书实际由合作的 CA 签发，颁发者一栏显示的是 CA 的名称而不是云厂商，看到陌生名字先对照自己的订单。
- **不认识的主机名。** 可能是别的部门自行搭建的系统、被遗忘的测试环境，最坏的情况是有人控制了你的某个子域名。
- **数量异常。** 证书突然大量出现，可能是自动化脚本陷入循环，也可能是 ACME 账户被盗用。

发现未经授权的证书，联系签发它的 CA 要求吊销；按照 Baseline Requirements，CA 必须调查处理。

## 隐私问题：CT 会公开主机名

公网证书 [SAN](https://ssl.sh/zh/glossary/san/) 列表里的每个名称都会被公开，通常在签发后几分钟内。`vpn.example.com`、`jenkins.example.com`、`test-newclient.example.com` 这样的名字会暴露内部架构，有时还会泄露业务计划。自动化扫描器也在盯着 CT 日志，新主机名一出现就会被探测。对于刚装好、还没完成初始化设置的网站程序，这是实实在在的风险。

能减少暴露的办法不多：

- **用通配符证书**（`*.example.com`），日志里只出现通配符。代价是一把私钥保护很多台主机，见 [通配符证书](https://ssl.sh/zh/glossary/wildcard-certificate/)。
- **纯内部系统用私有 CA**，链到本地信任根的证书不会进日志。
- **不要把秘密写进主机名。** 写进公网证书的名字，就当作已经公开。

在 CT 第二版标准化期间，曾有人提议在日志中隐去部分域名，但浏览器从未采用。

## RFC 6962 与 RFC 9162

RFC 9162 于 2021 年 12 月发布，定义了 CT 2.0，并在形式上取代了 RFC 6962，但实际部署的生态仍然使用第一版的数据结构。浏览器校验 v1 SCT，CA 内嵌 v1 SCT 列表，static-ct-api 改的是日志的发布方式，数据格式仍沿用 v1。Apple 甚至要求至少一个 SCT 来自 RFC 6962 日志。实践中说“CT”，指的就是 RFC 6962 的数据，通过原接口或 static-ct-api 提供。

## CT 做不到什么

CT 是一套发现机制，边界很清楚：它不能阻止错误签发，不负责吊销，而且依赖有人真的去监控日志。它也不说明网站是否可信：钓鱼网站的证书和银行的证书一样会被记录。把它和限制签发的 [CAA 记录](https://ssl.sh/zh/learn/caa-records/)、以及处理问题证书的吊销机制（见 [OCSP 与 CRL](https://ssl.sh/zh/learn/ocsp-and-crl/)）配合使用，才构成完整的防线。
