中间CA被攻破:当信任链断裂时
eMudhra中间CA被攻破事件揭示弱密钥如何瓦解Web PKI信任。了解中间证书的重要性,以及如何测试和修复客户端。

这个说法听起来有点反常:最严重的证书颁发机构(CA)事故,往往不是攻击者闯进来造成的。最近的 eMudhra 中间CA被攻破事件就是例子。八把中间CA私钥可以直接从证书本身恢复,完全不需要入侵,原因是CA自己的密钥生成仪式产生的私钥弱到离谱,其中一把的值居然就是数字4。没有人偷走这些密钥,它们一出生就已经是被攻破的。这种失败模式比任何数据泄露都更吓人,因为你没法靠轮换凭据、打补丁来修复。信任本身从第一天起就是有缺陷的。
如果你的系统有任何在浏览器之外发起TLS连接的场景,而几乎每个人都有,这件事就值得你花时间关注。浏览器在几天内就完成了防护。而生态的其他部分,比如定时任务里的curl调用、固定使用certifi的Python服务、内置根证书库的Go二进制文件,仍在追赶。下面我会梳理到底发生了什么,为什么中间CA被攻破在性质上比终端证书泄露严重得多,以及这次参差不齐的修复工作揭示了现代互联网吊销机制的哪些现状。
eMudhra事件的真相
根据CA在Mozilla问题追踪系统中提交的初步评估,事情的经过平淡得令人痛心。密钥生成仪式脚本是CA创建最敏感密钥时所用的受控、可审计流程,这里为了测试密钥包裹与解包的导出流程,经批准对其做了一项修改。修改后的代码存在缺陷,导致HSM上额外生成了一组ECC密钥,而这些密钥是弱的。不是那种“熵值降低”的弱,而是随便从公开证书就能算出来的弱。
想想这意味着什么。ECC私钥本应是一个256位的随机数。整个方案的安全性依赖离散对数问题:给定公钥,求出私有标量在计算上应当不可行。但如果你的“随机”标量只有一个字节,那么公钥不过是生成元乘以这个字节的结果,任何人在笔记本上几微秒就能穷举全部256种可能。据报道,八把密钥中的一把是整数4。这不是传统意义上的“被攻破”,而是一张从来就不安全的证书,却签发自一个Mozilla、微软、苹果和Chrome都信任的根证书。
报告此问题的研究者Wayne,用八把私钥分别对一段消息签名,并把签名提交给根证书计划,以此证明自己确实持有这些私钥。任何人只需几条OpenSSL命令就能验证:从每张中间证书中提取公钥,再检查消息签名能否用它验证通过。密码学的密钥持有证明之所以既优雅又令人不寒而栗,正是因为它没有模糊空间,没有“我们非常重视安全”之类的公关烟雾。数学要么成立,要么不成立。这次,它成立了。
为什么中间CA被攻破比终端证书泄露更严重
当终端证书的私钥泄露时,比如你的 api.example.com 私钥被传到了公开的GitHub仓库,影响范围就是一个主机名,如果是通配符证书也就几个。你吊销证书、重新签发、继续工作。麻烦,但不至于致命。
中间CA的私钥则完全是另一回事。Web PKI的运作方式是一条签名链:根CA(离线保存,防护级别堪比核材料)为中间CA签名,中间CA再为服务器实际出示的终端证书签名。只要持有某个中间CA私钥的人,在密码学意义上就等同于这个CA。他们可以为 google.com 签发一张有效证书,为你的银行签发,为你的内部SSO域名签发,而所有信任该链的客户端都会毫无异议地接受。没有速率限制,没有可以求证的中心权威,也无法区分一个伪造但有效的签名和合法签名。
eMudhra事件把这个问题放大了八倍。涉事的中间证书有些还通过Sectigo根进行了交叉签名,最终进入了数十亿台设备上预装的信任库。从有问题的证书被签发,到事件披露,大约一年半的时间里,任何信任这些中间证书、又没有强制执行证书透明度(CT)检查的客户端,都可能被只要肯费力恢复密钥的人冒充。这就是那段窗口期。我们并不知道是否有人利用过它,除非CT日志碰巧捕获到异常或者观察到实际攻击,否则可能永远无法得知。
这就是为什么根证书计划对中间CA事件的严重程度判定,远高于终端证书事件。撤销一个中间CA,意味着它签发过的每一张证书都会失效,成千上万的网站会同时瘫痪。Symantec的不信任事件历时数年,是个典型例子,说明当一个CA的运营被认定不可信时,完整修复有多痛苦。这套体系是有效的,但它的运作方式更像截肢,而不是手术。
无心插柳的功臣:证书透明度
这个故事里最值得多讲一讲的部分是:Chrome、Safari、Firefox和Edge在有人发现问题之前,其实就已经受到了保护。这不是因为吊销机制,而是因为证书透明度。
强制执行CT的浏览器要求,它们接受的每一张公共信任证书都必须记录在公开的、只能追加的CT日志中。被攻破的eMudhra中间证书在相关期间没有任何CT日志记录,这意味着攻击者用这些密钥签发的任何终端证书,都会被强制执行CT的客户端拒绝,因为它们无法提供有效的签名证书时间戳。伪造的证书必须先被公开发布才能被相信,而一旦发布,就会立即暴露。
CT的设计初衷是事后发现错误签发,让恶意证书可被察觉。而在这次事件中,它起到了预防性控制的作用:对浏览器用户群而言,这些被攻破的密钥几乎毫无用处,而浏览器正是大规模拦截攻击最有价值的目标。对于大多数工程师从不会想到的一块基础设施来说,这是一个真正的好消息。
但是,我得承认自己乐观的边界在这里:CT强制执行基本上是浏览器的特权。互联网上绝大多数TLS客户端根本不检查SCT。你的curl命令不检查,你的Python requests 调用也不检查,回传数据到厂商云端的物联网设备同样不检查。对于这些客户端,唯一的防护是吊销数据能及时到达信任库,而这正是故事变得难看的地方。
吊销缺口:浏览器与其他一切
浏览器厂商处理得很好,十年前搭建的基础设施值得称赞。Mozilla从十多年前就开始运行OneCRL,这是一种用于推送中间证书和根证书不信任决定的机制。这次事件中,Firefox用户在几小时内就得到了修复,完全不需要更新浏览器。Chrome的CRLSets和苹果的同类机制也在几天内在各自平台上完成了同样的工作。CA撤销了中间证书。从浏览器用户的角度看,这次事件还没开始就已经结束了。
再看看非浏览器的世界。修复清单读起来像一份软件供应链盘点:Ubuntu、Debian、Fedora、Alpine、Arch、Gentoo的ca-certificates包更新;新的NSS版本;新的curl CA证书包;Python的certifi;Rust的rustls-webpki和webpki-roots;Go的小版本发布;跨三条发布线的Electron补丁版本;Composer的ca-bundle;Elixir的castore。每一个都是独立的制品,发布节奏各不相同,由各自独立的更新机制分发。有些在披露数日后仍未完成。
还有一类问题让我夜不能寐:那些把自己的CA证书库打包进二进制文件的软件。去年构建的一个静态链接Go服务,把根证书直接编译进了产物里。要修复,只能重新构建并重新部署,因为根本没有可以打补丁的系统包。再乘以镜像仓库里每一个内置 /etc/ssl/certs 层的容器镜像,每台桌面上的每个Electron应用,每台联网设备上的每个固件镜像,问题的全貌就清晰了。系统信任库只是最容易的部分。我们之前写过嵌入式和OT设备如何把安全事件变成持续数年的麻烦,而被攻破的CA正是这类设备永远不会被修复的典型事件。

没人负责的信任库长尾
这次事件里有一个特例值得单独成段,因为它恰好说明了问题:macOS。苹果平台及时在操作系统层面屏蔽了被攻破的中间证书。但系统自带的 /usr/bin/curl 验证的是 /etc/ssl/cert.pem,这个文件没有被更新,而且它不检查吊销状态。于是你可能有一台打满补丁的Mac,Safari拒绝了伪造证书,同一台机器上的curl却欣然接受。同一台机器上两个信任决策,给出了相反的答案。
真正的教训在于这种碎片化。我们经常把“Web PKI”当作一个统一的系统来谈论,但它实际上是几十个性质迥异的系统:
- 浏览器:基于推送的吊销(OneCRL、CRLSets)、CT强制执行、自动更新。修复时间以小时到天计。
- 操作系统信任库:包管理器更新(ca-certificates、ca_root_nss)。修复速度取决于发行版的发布节奏,以及机器是否真的会打补丁。
- 语言生态:certifi、webpki-roots、Go内嵌根证书、Node内置的Mozilla证书库。修复意味着发布新版本,然后等待成千上万个项目升级依赖。
- 编译产物与镜像:二进制文件、容器、固件。修复意味着重新构建并重新部署,实际上这会留下一条持续数年的脆弱长尾。
- 物联网与嵌入式:往往根本没有更新途径,实际上是永久暴露。
浏览器在这种场景上投入了十年,而其他领域几乎没有人投入。Mozilla方面的一位上游评论者说得很直白:浏览器生态之外,对吊销机制几乎没有投入,而对这些客户端而言,这类事件是个巨大的问题。这与我运维基础设施时的所见完全一致。如果你处理过云身份认证日志记录中的盲区,就会认出这种模式:关键路径有完善的监控,而长尾则是一间黑屋子。
如何检查你的客户端是否仍然存在漏洞
理论讲完,你应该真正测试一下自己的资产,而TLS的好处在于可以通过实测来验证。社区成员搭建了一些主机,使用被攻破的中间证书签发的证书提供服务;如果你的客户端连接时没有出现证书错误,那就说明它仍然信任这些证书。测试curl或任何命令行工具的通用方法大致如下:
# A certificate error here means you're protected.
# A successful response means this client still trusts a compromised intermediate.
curl -v https://dv-g3b-emudhra.we-have-a-problem.com/
# You can also test whether a client will accept a forged cert for an
# arbitrary hostname by pointing it at a test server:
curl -v https://example.org --connect-to example.org::2.29.126.86:
在所有关键环境中都运行一遍:开发者笔记本、CI运行器、容器基础镜像、服务器集群。各环境的结果会有所不同,而这些差异恰恰就是重点。以下是快速盘点需要升级项的清单:
- Go服务:使用Go 1.27.3或1.26.10及以上版本重新构建,因为根证书已编译在其中。
- Python:certifi需升级到2026.10.19或更高版本(也要检查
pip和uv的版本,它们各自自带证书包)。 - Rust:rustls-webpki 0.103.16,以及webpki-roots / webpki-root-certs 1.0.10。
- Node.js与Electron:各发布线上待发布或已发布的补丁版本,请逐个检查实际分发的制品。
- 系统证书库:Ubuntu、Debian、Fedora、Alpine、Arch、Gentoo的ca-certificates包更新已经发布;撰写本文时,FreeBSD的ca_root_nss仍在等待发布。
如果等不及软件包更新,大多数Linux发行版允许你手动取消信任受影响的根证书。在Debian/Ubuntu上,只需在 /etc/ca-certificates.conf 中给相应证书加上 ! 前缀,然后运行 update-ca-certificates;在Fedora/RHEL系列上,把根证书放入 /etc/pki/ca-trust/source/blocklist/,然后运行 update-ca-trust。NixOS则有一个简洁的声明式选项:
security.pki.caCertificateBlacklist = [
"Comodo AAA Services root"
"emSign ECC Root CA - G3"
];
注意你在这些变通方案中实际取消信任的是什么:这些中间证书所链接的根证书。这就是PKI修复中的钝器现实。在大多数信任库工具中,并没有“只取消信任某一个中间证书”的原语,所以你只能把根证书加入黑名单,接受对无关证书造成的附带损失。紧急情况下这是正确的取舍,但它终究是一种取舍。
我的反向观点哪里站不住脚
开头我主张,自身造成的密钥生成失败比数据泄露更糟。那就坦白说说这个说法在哪里站不住。传统的数据泄露,比如DigiNotar,至少说明CA在攻击者得手之前是能胜任工作的,而整个体系恰恰押注于CA的专业能力。一个生成私钥“4”的密钥仪式,则意味着审计控制、HSM流程、合规检查表,没有一个环节捕捉到了CA最敏感操作中的灾难性缺陷。这不是对手的问题,而是保障能力的问题,而保障能力恰恰是CA出售的全部产品。
我的论点确实有站不住的地方:数据泄露更难防御,而且可能悄无声息地持续更久。一个谨慎窃取中间CA密钥的攻击者,可能只在针对性拦截时少量使用,却从不触碰任何强制执行CT的客户端。而弱密钥则任何人扫描公开证书都能发现,这恰恰就是这次事件被暴露的方式。有人会说,灾难性但显而易见的失败,胜过隐蔽却有针对性的失败。我不完全认同,但也无法反驳。事实是,两种失败模式最终都指向同一个结果:一个必须被取消信任的中间证书,以及一长串要过好几个月才会收到通知的客户端。
你应该实际怎么做
你无法修复Web PKI本身,但你可以缩小自己在它下一次失败中的暴露面:
- 测试,别假设。用受影响证书链的主机去探测你的客户端。这只需要一个下午,而且结果可能会让你吃惊。
- 重新构建编译产物。Go二进制和容器镜像自带信任库。在你重新部署之前,“我们已经修补了基础镜像”毫无意义。
- 盘点你的信任库。没有列出来的东西就无法修复。把certifi副本、内嵌证书包和Electron应用都算进来,把它们当回事,因为它们确实重要。
- 尽量使用系统信任库。每一个内嵌的证书包,都是你迟早会忘记发布的补丁。统一使用操作系统的信任库,并不能彻底消除问题,但至少让你只需盯住一个入口。
- 关注CT与吊销生态。有些项目正致力于把浏览器级别的吊销机制带给非浏览器客户端,它们值得支持;这次事件大概是它们能争取到的最有力的资金论据。
- 把CA事件当作安全事件处理。它们应该呼叫相关人员,触发一次资产盘点,并形成书面记录,就像处理泄露的凭据一样。因为它们本质上就是安全事件。
一个令人不太舒服的总结:Web PKI的紧急制动装置,恰好在最不需要它的客户端上运作得很好,因为CT已经为它们提供了保护。而真正需要这个制动装置的客户端,比如无头服务器、嵌入式设备、内嵌证书包的程序,以及被遗忘的系统,大多根本没有它。下一次中间CA被攻破,只是时间问题,不是会不会发生。你唯一能控制的变量,是你自己的资产有没有察觉。


