证书

证书透明度(CT)详解:日志、SCT 与证书监控

作者: · 最后核实

证书透明度(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)。

                    根哈希(签名后即 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。

 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 网站证书的输出(签名部分已省略):

echo | openssl s_client -connect letsencrypt.org:443 -servername letsencrypt.org 2>/dev/null \
  | openssl x509 -noout -issuer -dates -ext ct_precert_scts
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 天证书。

证书不满足政策时,Chrome 会显示 NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED。链到用户或企业自行安装的根证书的证书不要求 CT,所以 私有 CA 签发的内网证书不用进日志。

监控自己域名的证书

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

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

本站的 CT 证书搜索 在浏览器里做同样的查询。查看结果时重点关注:

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

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

隐私问题:CT 会公开主机名

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

能减少暴露的办法不多:

  • 用通配符证书(*.example.com),日志里只出现通配符。代价是一把私钥保护很多台主机,见 通配符证书。
  • 纯内部系统用私有 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 记录、以及处理问题证书的吊销机制(见 OCSP 与 CRL)配合使用,才构成完整的防线。

常见问题

服务器需要为证书透明度做什么配置吗?

几乎不需要。公网 CA 会把 SCT 直接嵌进证书,任何服务器只要部署这张证书就满足 CT 要求。通过 TLS 扩展发送 SCT 是可选的,很少有人用。

能不能让某个子域名不出现在 CT 日志里?

只要它写在公网可信证书里就不能。可以改用通配符证书,这样日志里只出现 *.example.com;纯内部系统可以用私有 CA,因为链到本地安装根证书的证书不要求 CT。

NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED 是什么意思?

Chrome 收到了一张公网可信证书,但随附的有效 SCT 不足以满足它的 CT 政策。通常是 CA 的问题(比如 SCT 来自 Chrome 已不再接受的日志),或者是企业内网的 HTTPS 检测设备造成的;重新签发证书一般就能解决。

CT 和吊销检查是一回事吗?

不是。CT 让签发行为公开可见,便于发现问题;它不告诉浏览器某张证书是否已被吊销。吊销靠的是 CRL、OCSP,或 CRLSets、CRLite 这类浏览器机制。

资料来源

  1. RFC 6962:Certificate Transparency
  2. RFC 9162:Certificate Transparency Version 2.0
  3. Chrome Certificate Transparency Policy
  4. Chrome CT Log Policy
  5. Apple's Certificate Transparency policy
  6. MDN:Certificate Transparency
  7. Let's Encrypt:Certificate Transparency (CT) Logs