给互联网发证书的机构,谁来监督它们?Cloudflare 开源了答案
2026/5/7 23:31:07 网站建设 项目流程

从一次黑客攻击说起

2011 年,荷兰证书颁发机构 DigiNotar 遭到入侵。攻击者利用这次入侵伪造了*.google.com的证书,并用它冒充 Gmail,对伊朗用户实施中间人攻击,试图窃取个人信息。

这件事之所以被发现,是因为 Google 在自己的服务中使用了"证书固定"(Certificate Pinning)技术,能够检测到与预期证书不符的情况。但证书固定本身并不适合大规模推广——你不可能给每一个网站都预先内置它应该使用哪张证书。

这次事件,以及类似的一系列攻击,推动 Google 的一个团队在 2013 年提出了**证书透明度(Certificate Transparency,CT)**机制。其核心思想很简单:所有公开颁发的证书,都必须记录在一个任何人都可以审计的公开日志里。

从此,CA 机构的每一次颁证行为都留下了公开可查的痕迹。截至今天,全球已有超过170 亿张证书被记录在 CT 日志中,CT 机制也于 2024 年荣获互联网安全领域的重要奖项 Levchin Prize。


先搞清楚这个生态里有哪些角色

CT 生态由四类参与者构成,理解它们的分工是读懂后续内容的前提。

证书颁发机构(CA):受信任的组织,代表网站运营者签发证书。浏览器的根证书列表里有 150 多个 CA,理论上任意一个都可以为任意网站签发证书——这正是问题所在。

CT 执行客户端:主要是浏览器,如 Chrome、Safari、Firefox。它们只接受符合 CT 策略的证书,例如要求证书必须提交到至少两个独立运营的 CT 日志。

日志运营商:运行 CT 日志的组织。日志是一个只增不减的公开列表,CA 向日志提交证书后,会得到一个"签名证书时间戳"(SCT),用来向浏览器证明该证书已被记录。

监控方(Monitor):持续爬取 CT 日志、验证其行为是否正确的第三方机构,同时帮助网站运营者发现被错误颁发的证书。

Cloudflare 本身同时扮演了其中两个角色:运营 Nimbus CT 日志,以及通过 Merkle Town 仪表盘提供 CT 监控服务。


运营一个 CT 日志,到底有多难?

CT 日志对运营者的要求极为苛刻,核心体现在两个维度:完整性可用性

完整性:容错率为零

CT 日志的设计是追加式的,任何历史记录都不能被篡改或删除。更关键的是,日志不能对不同客户端呈现不同的视图——它必须在整个生命周期内保持完全一致。

这种完整性要求几乎不留任何余地。历史上,一次硬件故障导致的单个比特翻转就足以让一个 CT 日志产生错误输出,进而被 CT 程序取消资格。即便是软件更新,如果引入了破坏正确性的变更,也无法简单回滚——因为日志一旦发出的承诺(SCT)就必须兑现。

最常见的致命故障是:日志已对某张证书签发了 SCT,却在将其写入持久存储之前崩溃,导致无法将该证书纳入日志——这是对承诺的违背,后果是直接失去资格。

可用性:99% 在线率说来容易,做到很难

Chrome 的 CT 日志策略要求,每个 API 端点在 90 天滚动周期内的平均在线率不低于 99%。此外,日志必须在 24 小时内(称为"最大合并延迟",MMD)将已签发 SCT 的证书纳入日志。

然而,旧版 CT API(RFC 6962)的读取接口是动态的、难以缓存的。客户端可以请求任意范围的日志条目,服务端需要实时构造各种包含证明(Inclusion Proof)。为了服务这些请求,CT 日志服务器背后需要维护 5 到 10 TB 规模的数据库,每天处理数千万次请求,带宽成本和运维复杂度都极高。

Cloudflare 自己的 Nimbus 日志也曾因这些原因遭遇过重大故障。最近一次是 2023 年 11 月,数据中心完全断电,导致日志长时间中断。

正是这些运营门槛,导致全球目前只有包括 Cloudflare 在内的六家机构在运营 CT 日志。如果其中一两家退出,整个 CT 生态的稳定性就会受到严重威胁。


下一代设计:Static CT API

2024 年 5 月,Let’s Encrypt 发布了 Sunlight,这是基于十年 CT 运营经验设计的下一代 CT 日志实现,对应的规范被称为Static CT API。它从根本上改变了 CT 日志的数据组织方式。

静态分块(Tile):让缓存变得自然

Static CT API 将日志数据组织为一系列静态的、可缓存的瓦片(Tile)。日志运营商可以直接用 S3 兼容的对象存储服务(如 R2、S3)提供这些文件,并通过 CDN 加速,不再需要专门的 API 服务器来处理动态查询。

这一改变从根本上解决了高可用的问题——静态文件的服务可靠性远高于动态 API,CDN 缓存也能大幅削减带宽成本。

去重中间证书:节省存储空间

全球受信任的中间证书和根证书数量有限(数量级在数千级别)。旧版设计中,每条日志条目都会完整存储一遍证书链,大量重复。Static CT API 只存储颁发者证书的哈希值,客户端通过哈希从单独的端点查找完整证书,显著降低了存储开销。

SCT 内含索引:消除合并延迟

旧版设计中,日志会在接收到证书后立即返回 SCT,然后在后台异步将其写入日志。这个"先承诺、后写入"的机制是合并延迟(MMD)问题的根源——如果写入失败,承诺就无法兑现。

Static CT API 改变了这个流程:日志只有在条目真正被写入并排序之后,才返回 SCT,且 SCT 中直接包含该条目在日志中的索引位置。延迟由此从"随时可能超过 24 小时"变为"通常只有几秒",同时也消除了承诺无法兑现的风险。

有了索引,SCT 审计也变得更高效:客户端无需再通过哈希反查,直接根据索引下载对应的分块数据即可验证。


Azul:Cloudflare 在 Workers 上构建的 CT 日志

基于上述规范,Cloudflare 开发并开源了自己的实现,命名为Azul(取自葡萄牙语和西班牙语中的彩色陶瓷砖"azulejos",呼应了 Static CT API 的分块概念)。

项目地址:github.com/cloudflare/azul

设计原则

部署在 Cloudflare 自己的全球网络上。2023 年 11 月的数据中心故障让团队深刻意识到,依赖单一集中式数据中心的方案脆弱性太高。将日志部署在全球分布的高可用网络上,是应对这一问题的根本思路。

用 Rust 实现,完全跑在 Workers 上。Cloudflare 有着"用自己产品"的文化传统——Azul 完全基于 Cloudflare 的 Developer Platform 构建,包括 Workers、Durable Objects、R2 和 KV。这样做的额外好处是,开发过程中发现的 SDK 缺陷和产品痛点,可以直接反馈给内部团队改进,同时也确保了任何外部开发者都能用同样的方式部署自己的 CT 日志。

架构拆解

监控 API(读取):Cloudflare R2

静态分块文件天然适合放在对象存储里。R2 提供全球强一致性读取,支持海量数据,并可配置缓存和压缩策略,不限读取次数。这部分几乎没有什么设计难度。

提交 API(写入):Workers + Durable Objects

写入流程是真正的挑战所在。

流程设计如下:

  1. Frontend Worker接收来自 CA 的证书提交请求,进行初步验证,查询去重缓存,然后将条目发送给后端排序。
  2. Sequencer(Durable Object)是日志的核心状态机。每个 CT 日志对应一个 Durable Object 实例,负责定期(每秒一次)将待处理的条目批量写入 R2,更新日志的最新检查点(Checkpoint),并向等待响应的前端 Worker 发出信号。

Durable Objects 的强一致性事务存储,完美契合"锁后端"的需求——保存当前检查点这一关键状态。告警(Alarm)机制则用来每秒触发一次排序任务,类似于传统服务器中的定时任务。

去重缓存:内存 + Workers KV

去重缓存需要在 50 GB 以上的规模下高效运作。Durable Objects 的存储上限和 D1 单库容量都无法满足,直接从排序循环中远程读写又太慢。最终方案是分两层:

  • 短期内存缓存:固定大小,处理分钟级别内的重复提交,速度极快;
  • 长期缓存:Workers KV,一个全局低延迟、最终一致的键值存储,没有存储量限制,用于跨会话的长期去重。

性能瓶颈与突破

初版架构上线后,性能测试显示日志每秒只能处理 20-30 个新条目,而目标是 70 个以上(参考 Nimbus2025 日志的实际水位)。

根本原因在于:单个 Durable Object 是单线程的。它必须同时处理来自前端的提交请求、每秒一次的排序任务、向 R2 写入十几个分块文件、向 KV 写入去重记录……任务数量远超单线程的调度能力,导致排序任务频繁被延误。

解决方案是引入一个中间层:Batcher

前端 Worker 通过一致性哈希将请求分配到多个 Batcher DO,Batcher 负责将多个请求缓冲后批量发送给 Sequencer,减少 Sequencer 的直接请求数量。同时,去重缓存的写入也交由 Batcher 处理,进一步释放 Sequencer 的资源。

这一架构将 CT 日志的吞吐量从 20-30 req/s 提升到了500 req/s 以上,同时保持了每次排序只需 1-2 秒的低延迟。


已经快了,但未来的挑战更大

CT 生态正在面临两个即将到来的重大压力,Static CT API 和 Azul 的出现恰逢其时。

证书寿命大幅缩短。CA/B Forum 正在推进一项提案,计划到 2029 年将公开 TLS 证书的最长有效期从 398 天压缩至 47 天。Let’s Encrypt 走得更快,计划在 2025 年底前提供有效期仅为 6 天的短期证书。根据 Merkle Town 的数据粗算,这些变化将使 CT 生态中需要记录的证书数量增加16 到 20 倍

后量子证书的体积膨胀。现有的 P-256 ECDSA 证书体积不到 1 KB,而换用后量子算法(如 ML-DSA44)后,同一张证书的体积将膨胀到 4.6 KB 左右——意味着每条日志条目需要存储的数据量约是现在的4 倍

将这两个因素叠加,CT 日志面临的存储和带宽压力将比今天高出数十倍。Static CT API 的分块缓存架构和运营成本的显著下降,让更多组织有条件参与到 CT 日志运营中来,从而将压力分散到更多节点上。


总结

Azul 这个项目,表面上是 Cloudflare 开源了一个证书透明度日志的实现,但它背后展示的东西更值得关注:

一个关键基础设施如何从少数玩家把持走向更广泛的参与。全球只有六家 CT 日志运营商,这是一个高度脆弱的现状。降低运营门槛,让更多组织能够以合理的成本加入,是 CT 生态健康发展的必要条件。Static CT API 和基于 Workers 的实现,正是为这个目标服务的。

Cloudflare 的产品哲学在工程实践中的体现。自己先用、遇到 Rust SDK 缺陷就提 PR、把实际痛点反馈给产品团队——这种从内部压测开始的迭代方式,比单纯的 beta 测试更接近真实负载。

两个即将到来的挑战的预警。短寿命证书和后量子证书不是遥远的议题,它们正在以可预期的时间表向 CT 生态逼近。现在开始建设能够应对 20 倍流量增长的基础设施,不是超前,而是刚好够用。

代码已开源,测试日志已上线。如果你有兴趣深入了解,可以直接前往github.com/cloudflare/azul查看。


参考来源:Cloudflare Blog — “A next-generation Certificate Transparency log built on Cloudflare Workers”

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询