私钥是数字 4:一次拖了全行业的密钥事故
先说一个数字:4。上周,安全研究员 Scott Helme 在自己的笔记本电脑上,不到一秒恢复了八把 CA 私钥——其中一把就是整数 4,其余七把也都是 256 以下的整数。这八把私钥本来应该保护的是:谁有权给互联网上的任意网站签发「可信」证书。这场事故的编号叫 CVE-2026-111943,Go 语言上周的紧急版…
私钥是数字 4:一次拖了全行业的密钥事故
先说一个数字:4。上周,安全研究员 Scott Helme 在自己的笔记本电脑上,不到一秒恢复了八把 CA 私钥——其中一把就是整数 4,其余七把也都是 256 以下的整数。这八把私钥本来应该保护的是:谁有权给互联网上的任意网站签发「可信」证书。这场事故的编号叫 CVE-2026-111943,Go 语言上周的紧急版本就是为它发的。
把背景铺开。你在浏览器里访问一个网站,网站出示一张证书,证明「我就是这个域名」。证书不是凭空来的:网站证书由中间 CA 签发,中间 CA 挂在根证书下面,根证书预装在你的操作系统和浏览器里。拿到一把中间 CA 私钥的人,可以给任何域名签证书——银行、邮箱、政府网站——而你的软件会照单全收。
这八把私钥属于 eMudhra,一家印度 CA,品牌叫 emSign。2025 年 4 月 30 日,他们办了一场密钥仪式,批量生成 24 个中间证书。仪式在经过认证的硬件安全模块(HSM)上进行——但 HSM 的认证说的是设备可信,管不了设备里跑的脚本。eMudhra 事后解释:脚本出错的环节生成了第二套弱密钥,和正常密钥的标签长得相似,团队拿着弱的那一套做了证书签名请求。发进各大根商店的,就是弱的那套。
弱到什么程度?中间证书用的是椭圆曲线 P-384,私钥本该是一个接近 384 位的随机数。这八把的实际取值在 4 到 237 之间。椭圆曲线的数学关系是:公钥 = 私钥 × 曲线上的固定点。私钥要是 4,你把那个固定点乘以 4,和证书里印着的公钥一比——对上了。挨个试,最多 255 次。研究者还提到,现在的 AI 智能体一个提示词就能做完这件事。
戏剧性的是,警报其实来过一次。2025 年 6 月,这些中间 CA 签发的六份吊销列表签名验不过——因为先用了原始密钥去签。这个反常当时没被当成警报。
正式披露在 2026 年 10 月 17 日晚上。一位独立研究者用每把私钥签名了一条固定消息,把证据交给了各大根计划。Chrome 在 18:05 收到报告,19:45 推出拦截——一百分钟。Mozilla 当晚 23 点前推完。苹果 19 日,微软 20 日。翻查证书透明度日志,没有找到一张冒签的证书:从 2025 年 4 月到 2026 年 10 月,一年半里要么没人发现,要么发现的人没动手。
轮到 Go 出场。Go 的 TLS 校验走自己的标准库 crypto/x509,信任库读系统的根证书目录。问题在于:Linux 系统的根证书包能自动分发「信任」——发行版更新一下,新根就到亿万台机器上;但它没有「中间证书被撤销」这个频道。撤销状态要靠应用主动去查 CRL 或者 OCSP,而 Go 的校验默认不查。更麻烦的是,这八个中间证书有的挂着 Sectigo 的 AAA 老根的交叉签名——把 eMudhra 自己的根摘掉,这条路依然通。攻击者拿泄露的私钥签一张任意域名的证书,握手时把撤销的中间证书一并递上,链条一路验证到可信的根,校验函数原样把这条链返回给调用方。应用一看:验证通过了,可信。
修复的办法很直接:把八个公钥的 SHA-256 哈希硬编码进标准库。校验函数在筛候选链时,碰上含这八个哈希的链就整条删除,Windows 和 macOS 走系统校验的路径同样过滤。升级到 1.27.3 或 1.26.10 就有了。Debian 干得更狠,直接把两个根从系统信任包里摘了。
这次事故最值得记的一层:信任的分发是推的,撤销的分发是拉的。根证书随系统更新自动到你机器上;撤销信息却要应用自己去查,而大多数应用不查。这一周全行业都在把「拉」改成「推」:浏览器的吊销列表自己拉取、Go 把哈希编进二进制、发行版摘根。但推送有边界——没人更新的旧容器、自带一份 CA 文件的语言运行时,这些角落里,信任还停在 2025 年 4 月。证书校验返回「通过」,说的只是签名对、没过期、链得到根;它没说这把密钥没泄露。验证器没说的话,调用方一直当成它说过。
参考:Go issue 82345 / golang-announce 2026-10-20;eMudhra 与 Cloudflare、Mozilla、Chrome Root Program 的公开通报(2026-10-19 至 21);建议:Go 升级 1.27.3 / 1.26.10。