信任的供应链:Web PKI的修修补补与DNSSEC的未竟之路

• 本文约6287字,阅读大致需要13分钟 • Security

前几天刚刚写了一篇《别了,SMTP mTLS》,其中一件让人哭笑不得的往事,是DigiCert在2024年因域名控制权验证(DCV)出现漏洞,本应按规定在24小时内吊销受影响的证书,却因为顾忌大企业客户的内部业务中断而未能及时执行。公共证书一旦兼作内部基础设施的凭据,紧急吊销就会遇到这样的阻力。Chrome后来在根证书策略中要求逐步分离客户端认证(clientAuth)用途;其中,2027年3月15日及以后签发的终端证书必须只包含serverAuth。邮件服务器之间原本相安无事的mTLS双向认证,就这么稀里糊涂地成了商业CA合规翻车的牺牲品。

正如周师傅说的:「这个世界不会再好了」。本周,在PHP、Node.js、Linux纷纷爆出重大漏洞之余,eMudhra和GoDaddy这两家CA也跟着爆雷了。

这些事背后是同一个问题:支撑整个互联网的Web PKI,远没有我们希望的那般严谨,更像是由一群水平参差不齐的商业机构靠各方妥协拼凑起来的「草台班子」。

草台班子撑起的全球信任

例子太多,我就挑最近爆雷的这两家。

先说eMudhra,这是一家印度的发证机构,其问题相当离谱:Scott Helme 写道:

One of eMudhra’s certificate authority private keys is the number 4.

实际上,这一批8个中间CA使用的是P-384椭圆曲线,但私钥标量全都不超过8位。其中6个用于TLS,2个用于代码签名。通常,当一家CA的私钥被盗时,还可以调查泄露的时间与范围,但吊销和停止信任仍然必不可少。而这一次,由于私钥本身的强度问题,任何人使用现有的普通硬件都可以瞬间穷举出私钥。这些中间CA证书在2025年4月签发,到2026年10月才被吊销和封禁。在此期间,不能排除有人使用这些弱私钥签发过证书。不过,Google的公告明确指出,封禁前CT日志中没有发现链向这6个TLS中间CA的证书,因此它们签发的伪造证书无法用于攻击默认强制检查CT的Chrome。这个结论并不能覆盖不检查CT的客户端。

更严重的是,许多非浏览器客户端,例如curl、Python、Node.js和Java程序,采用的并不完全是同一套验证体系,即使现在已经吊销了这些证书,让这些客户端收到并执行吊销或封禁信息,也是一个长尾过程,更遑论各种Internet of Things(Shit)设备了。

而GoDaddy这边,虽然与eMudhra的密钥安全事件相比没有那么离谱,但同样暴露出了重大问题。按其事故报告,签发的证书与CP/CPS中记载的证书配置不一致,因此GoDaddy启动了大规模证书替换和吊销。按其10月22日的最终统计,共有403,643张证书受影响,其中378,067张被吊销,另有25,576张已经过期。我在发薪日凌晨想要登录银行网站,结果惊喜地发现银行的证书被吊销了。OCSP给出的理由是superseded,也就是「已被替换」;这正是相关合规条款要求使用的原因码:

Cert Status: revoked
    Revocation Time: Oct 21 22:26:51 2026 GMT
    Revocation Reason: superseded (0x4)
    This Update: Oct 21 22:32:04 2026 GMT

和DigiCert类似,GoDaddy也未能在五天之内完成吊销,理由仍然是客户数量大、且涉及政府、金融和医疗服务提供者,需要协调证书替换,避免立即造成大面积服务中断,或者翻译成人话就是:大家都是草台班子。

两家CA的问题成因不同,后果也不同,但都反映了同一个问题:Web PKI在根证书库中内置了数十家受信任的根CA,背后又级联出数量更多的中间CA。这些机构分布在世界各地,工程水平参差不齐,受制于各自的属地法律与商业利益。而在现行的信任模型下,对没有受到名称约束等限制、且被客户端信任用于TLS服务端认证的CA而言,它们在域名签发权限上近似于「并联」关系:其中任何一家,都可能为任意域名签发证书。

也就是说,即使你自己的服务器配置与域名都做了妥善防护,只要这数十家根机构其中的一个出现问题,即使你不是他们的客户,也可能会受到影响。整体的安全性取决于这几十家商业机构里最弱的那一家,这很难说是一个健康的体系。

浏览器厂商的应对方案

浏览器厂商当然也没闲着。不过在过去十多年里,Web阵营并没有去重构这套并联的信任模型,而是在它上面叠床架屋,打了一层又一层补丁:

第一块补丁是域名的证书颁发机构授权(CAA)记录(RFC 8659)。域名所有者可以在权威DNS中发布一条CAA记录,声明「只允许某几家CA为我的域名签发证书」。但是,在架构上它纯粹是一种「君子协定」。CAA的约束力完全取决于CA在签发证书前是否主动查询并严格遵守这一规则。浏览器在TLS握手时不会用CAA来验证证书;RFC 8659也明确禁止这样做,因为当前的CAA记录并不代表证书签发时的授权状态。倘若一家CA的工程水平差到连基础的DCV验证逻辑都能写出Bug,指望它的CAA解析逻辑一定没有漏洞,恐怕也不现实;面对被攻破或怀有恶意的CA,CAA更是形同虚设。

第二块补丁是被视为Web PKI最大技术进步的「证书透明度日志」(RFC 6962)。Chrome等浏览器要求公开信任的证书满足各自的CT策略,客户端会检查签名证书时间戳(Signed Certificate Timestamp,SCT)。SCT可以随证书、OCSP stapling响应或TLS扩展提供,它表示日志承诺在规定时间内收录证书或预证书,并不等于客户端已验证实际收录。CT并不判断域名控制权,也不能阻止误发本身;但强制校验CT能拒绝未取得合规SCT的证书,让攻击者不能悄无声息地使用任意伪造证书。这次eMudhra事件就体现了这层保护的价值。不过,一张误发证书也可能正常进入日志,因此域名所有者仍需要监控CT,发现异常后再推动吊销和封禁。透明度没有消除对CA的信任,只是让滥用更容易被发现。

第三块补丁是长期面临分发难题的证书吊销机制。一旦证书发生私钥泄露或合规误发,传统的证书吊销列表(CRL,RFC 5280)需要客户端及时下载和更新,大规模列表会带来带宽与存储成本;在线证书状态协议(OCSP,RFC 6960)在客户端需要直接查询时,则会引入额外的网络延迟,并可能向CA暴露用户正在访问的站点。缓存和OCSP stapling可以缓解这些问题,因此并不是每次连接都要查询CA。不过,采用「软失败」(soft-fail)策略的客户端在查询超时或失败时仍会接受证书,攻击者阻断OCSP请求,就可能绕过这一项吊销检查。

CA/Browser Forum的SC-063投票从2024年3月起把OCSP改成了可选项,此后,Let’s Encrypt在2025年关闭了OCSP服务,Google Trust Services也从2025年下半年起不再为大部分证书链嵌入OCSP地址,Firefox 142起对DV证书也不再查询OCSP。因此在公网TLS上,即使服务器愿意做OCSP stapling,OCSP也已经在退场了。

为了改善这个问题,Google和Mozilla分别提供了浏览器侧的吊销信息分发机制。Google的CRLSets 包含紧急封禁信息,也从CRL中选取部分吊销记录,但并不覆盖全部吊销。Mozilla的CRLite 则将其覆盖的CT证书集合中的吊销状态压缩后定期推送给客户端,本地检查无需向CA暴露访问记录。早期CRLite采用级联Bloom filter,2025年部署的实现已改为基于Ribbon filter的Clubcard结构。

越修越窄的护城河与物联网泥潭

这一系列修修补补在很大程度上改善了Web的安全性,但是,代价是什么呢?

正如互联网先驱、BIND的主要作者之一、长期参与DNS标准工作的Paul Vixie 在2019年接受ESET访谈时所指出的那样:

「由于DNSSEC的标准化和部署耗费了太长时间,数字经济中的某些领域决定不再等待,直接假定DNSSEC已经死亡——其实它没有。于是,做Web的那帮人现在正忙着自己重新发明轮子,去实现DNSSEC最初被设计用来完成的目标。考虑到已经过去了二十年,我并不完全责怪他们失去耐心,但事实是,他们走错了路。互联网远比Web宏大得多,我们明明拥有DNSSEC这样能够服务于整个互联网的设施,所有人都应该站到它这边来。」

这些补丁基本上都长在浏览器里,因此带来了两个副作用:

其一,Web之外的互联网协议被边缘化了。无论是证书透明度的强制校验、CRLite的吊销列表分发,还是对劣质根证书的紧急拉黑,这些能力在Chrome、Firefox等现代浏览器中有现成的实现和更新渠道。而互联网上大量非HTTP协议(例如邮件传输、即时通讯、数据库连接、系统后台守护进程)不能仅靠加载同一份根证书库,就自动获得同等保护。这些机制并非只能用于浏览器,例如CRLite的代码已经开源,但其他客户端需要自行集成和维护。不仅如此,正如前文提到的客户端认证被剥离事件,以及CA/Browser Forum通过的证书有效期缩短计划 (2026年3月15日起上限为200天,2027年降至100天,2029年3月15日起为47天),都体现了Web PKI降低风险、推进自动化的方向,其代价却是将巨大的运维重构成本转嫁给了整个非Web互联网生态。

其二,物联网(Internet of Things(Shit))几乎无解。这次eMudhra事件中,Chrome与Firefox在收到报告的当天就通过CRLSet和OneCRL封禁了受影响的中间CA。不过,封禁这些密钥与移除eMudhra所有根证书不是一回事:Chrome公告中计划移除的是emSign ECC Root CA - G3,其余根证书仍在评估。但在广阔的物联网世界里,成千上万的嵌入式设备、工业网关、智能家电与车载系统,其中一些设备的固件直接打包了某个历史版本的根证书库。这些长生命周期的设备既没有能力运行复杂的浏览器级吊销推送组件,更缺乏高频、可靠的固件空中升级(OTA)机制。结果就是:即使浏览器厂商及时将某个CA拉黑,也无法阻止这些设备继续信任该CA签发的证书,或是任何人用泄露的私钥签出来的证书。eMudhra这批中间CA在2025年5月还拿到了Sectigo旗下AAA Certificate Services根的交叉签名,这是一个2004年的老根,广泛存在于各种历史版本的根证书库里。因此,即使设备从未信任过eMudhra自己的根,只要拿不到交叉证书的吊销信息,也可能沿着这条链信任这些弱密钥签出来的证书。

DNSSEC与DANE:并不优美的另一条道路

既然依赖数十家商业中介的并联信任模型如此脆弱,为什么能够将信任收敛回域名层级本身的DNSSEC与基于DNS的命名实体认证(DNS-based Authentication of Named Entities,DANE)迟迟未能成为主流?

Paul Vixie在同一场访谈中也坦率承认了它的缺陷:

「DNSSEC是一个比较特殊的问题,因为它并不优雅,在架构上算不上一个漂亮的协议,但它是可以被跑通的,而且确实有效。一旦将它运转起来,它就能够在HTTPS或TLS等协议之上更快速地建立起信任关系,而无需经历那条漫长的供应链去验证你究竟该不该信任你的通信对端。」

DNSSEC推了二十多年仍未普及,也不全是别人的错,它自己的问题也不少:

  1. 报文尺寸:在DNSSEC部署初期,受限于当时的算力与标准,一些区域采用了1024位RSA区域签名密钥。随着密码学演进,1024位密钥的安全性捉襟见肘;但若直接升级至2048位RSA,更大的密钥与签名会增加DNS响应体积,提高触发UDP分片或TCP回退的概率。在遍布老旧家用路由器与严苛防火墙的真实网络环境中,分片或带有扩展机制(EDNS0,RFC 6891)的大尺寸UDP报文很容易被丢弃,而大应答本身也方便了反射放大攻击。后来椭圆曲线算法(例如ECDSA P-256与Ed25519)通过缩小密钥和签名体积缓解了一部分问题;然而,大应答、分片与TCP回退的兼容性问题仍然存在。
  2. 运维负担与「自杀式」故障:普通DNS的委派错误也可能造成整个域名不可达,而DNSSEC又引入了严格的时间窗口(签名有效期)、复杂的区域签名密钥(ZSK)与密钥签名密钥(KSK)轮转机制,以及子区域与父区域之间委派签名者(DS)记录的跨系统同步,对运维的要求高了不少:一旦自动化签名脚本卡死或密钥轮转时序出错,启用DNSSEC验证的递归解析器可能将相关应答判定为bogus,并向普通查询返回SERVFAIL。影响范围与缓存、签名有效期及故障位置有关,并非全网同时失效。我时常会在DNS-OARC邮件列表上围观到各种事故。
  3. 否定应答的妥协:为了在离线签名机制下用密码学证明「某个记录不存在」,早期的NSEC记录按规范顺序指向区域中的下一个名称,形成环状链。外人可以沿链枚举名称及其记录类型,但这并不直接给出所有记录的内容,也不会跨越区域委派。后来为此引入的NSEC3(RFC 5155)哈希机制又进一步推高了协议的复杂性,以及权威服务器和验证器的计算开销。它也不能彻底阻止字典枚举,因此RFC 9276建议无特殊需要时优先使用NSEC,使用NSEC3时将额外迭代次数设为0。

不过,只要愿意跨过这些门槛,建立在DNSSEC之上的DANE(通过TLSA记录实现,RFC 6698)是一个相当不错的信任模型:

  • 授权路径唯一:Web PKI采用的是一种相当危险的「或」逻辑。在没有名称约束等限制时,任意一家受信CA都可能为你的域名背书;而在以根区密钥为信任锚的通常部署中,DNSSEC沿树状层级授权:从根域(.)到顶级域(例如.net),再到二级域名(例如delphij.net),只有沿着这条唯一权威路径逐级签名授权的公钥才具备合法性,路径之外的机构无权置喙。
  • 不再依赖公共CA背书:通过配置TLSA记录(例如使用3 1 1,即DANE-EE、SubjectPublicKeyInfo选择器与SHA-256匹配方式,直接锚定终端服务器公钥信息的哈希值),域名所有者可以直接声明:「访问我的服务时,只认这把特定的公钥」。在客户端支持DANE、正确验证DNSSEC并按策略拒绝不匹配连接的前提下,即便某家商业CA被黑客攻破,或是因为代码漏洞签发了伪造证书,客户端在握手阶段通过比对DNSSEC保护下的TLSA记录,就能直接拒绝连接。不再需要祈祷对方遵守CAA,也不需要担心证书透明度日志,或是吊销列表有没有及时推送到对方服务器。
  • 与上层协议无关:DNS记录按端口与传输层协议挂载(例如_25._tcp.mail.example.com)。它不关心上层跑的是网页、邮件还是其它私有协议。邮件服务器间传输已经有DNSSEC配合DANE的标准(RFC 7672),可以不依赖公共CA来认证接收方。

当然,这并不意味着信任链消失了:DNSSEC仍然依赖根、父区域、域名注册与DNS托管环节的安全。上级区域或注册账户被攻破、DNS签名密钥泄露,都可能破坏这套授权关系。TLSA和密钥轮换还必须考虑DNS缓存;物联网设备的信任锚、算法与验证器同样需要维护。DANE收窄了授权路径,却不能让这些工程成本凭空消失。

越挖越深的兔子洞

回看过去十几年,互联网安全基础设施像是在兔子洞里越挖越深:嫌底层协议推进太慢、运维太繁琐,于是在应用层用商业联盟和越来越复杂的客户端补丁搭起一套结构;每次有CA出事,就再加一层补丁,顺手把非Web协议和没法更新的设备往边上又推了一点。

Vixie在那场访谈里还说,每个拥有自己网络的组织,终究都得在这些问题上自我教育。在Web PKI里疲于应付CA的合规事故、越来越短的证书有效期和不断被砍掉的协议特性之余,回过头去认真看看DNSSEC与DANE,把信任的定义权收回到域名自己手里,或许是一条更值得走的路。