从“四个密钥”看弱密钥修补追踪:披露后如何核对吊销、替换与残余暴露
以 Cloudflare 对 eMudhra 弱密钥事件的处置为样本,说明漏洞披露后核对进度要分三条线:吊销凭证本身是否可信、依赖方信任存储是否真的拒绝该密钥、外部能否观测到滥用。文章给出可复核的核对清单,并指出探测比例会被流量偏斜、监控缺口和流量分类变化污染,不能直接当作修补进度。
- “CA 已发 CRL”和“我们已修补”都不是终点,CRL 的签名者和依赖方的信任存储要分别核对。
- 残余暴露比例必须连同探测设计一起读:端点配置、探测比例、监控缺口、机器人判定变化都会改变曲线形状。
- 本次材料只覆盖 Cloudflare 一侧的观测,其他客户端与信任库的具体状态待核实。
“四个密钥”这个说法容易引起误会:Cloudflare 在 2026 年 10 月 30 日的复盘里说的是 八把弱密钥,值分别是 4、56、66、115、155、156、230 和 237;其中最小的那个是 4——本应选一个 115 位数字,实际选了这个数(来源:Cloudflare 博客,2026-10-30)。
对开发者更有用的不是这个数字有多离谱,而是它把“吊销”和“替换”这两件事摆到了同一条时间线上,暴露出一个常见误判:把 CA 的声明当成进度,把一条曲线的拐点当成修补完成。本文按三条独立证据线整理核对方法,材料未覆盖的部分直接标为待核实。
一、先把“吊销”和“替换”拆开#
这两件事常被合并成一句“已经处理”,但它们的证据完全不同。
- 吊销是 CA 侧动作:签发 CRL、更新 OCSP、被信任库移除。它证明“这把密钥不该再被信任”,不证明“你的系统已经不再信任它”。
- 替换是依赖方动作:客户端、服务端、代理、SDK、设备固件里的信任存储不再接受该中间证书。它才是暴露面真正收缩的时刻。
本次事件里有一个必须记住的细节:eMudhra 宣布退出公共 CA 业务,声称是密钥生成脚本出错,但尚未公开该脚本;它先签了一份 CRL——用的可能是正确生成的密钥——随后又把这份 CRL 更正为用弱密钥签名(来源同上)。这意味着“能下载到 CRL”本身不构成吊销生效的证据,签名者是谁才是核对点。
另一个前提也来自同一份材料:受影响的中间私钥可以从公开证书中近乎即时恢复,因此任何未打补丁、且不强制 Certificate Transparency(CT,证书透明度)的客户端都会接受伪造证书。这与 DigiNotar、TÜRKTRUST 等历史事件不同——那些事件中密钥访问被限制在有限范围内。
二、替换要落到“拒绝哪些密钥”,而不是“删掉某个文件”#
Cloudflare 公布的做法可以当作一个可借鉴的处置样本,但它只是样本,不是通用模板:10 月 19 日当天先修补高影响系统,包括使用 Pingora、面向客户源站的出站代理,数小时内改为拒绝这些脆弱密钥;同时用 AI 辅助分析源码找其他信任点,四小时内完成全量分析,逐系统开单、由团队当天确认或修正,高影响立即修补,低影响限期完成。撰写时高优先级系统已全部修补,少量确认低影响的工单仍在处理。
落到一般项目,建议先枚举信任点再谈期限。常见位置包括:操作系统根存储、语言运行时自带 bundle(JVM cacerts、Python certifi、Node 内置证书)、容器基础镜像、出站代理与网关、SDK 内置证书、CI runner、移动端 WebView、IoT 固件。下面只是未执行的示意,路径随版本与环境变化,需按实际情况核实:
# 未执行示例:仅示意需要枚举的信任来源类别,不代表任何真实环境输出
ls /etc/ssl/certs # 系统信任库(路径因发行版而异)
python -c "import certifi; print(certifi.where())" # 运行时自带 bundle
# 还需人工核对:容器基础镜像、出站代理配置、SDK 内置证书、设备固件
核对标准建议写成“可出示的证据”,而不是“已通知”:配置 diff、拒绝日志、工单状态、镜像重建记录。材料没有给出具体配置命令,任何声称“照此配置即完成”的写法都需要另行验证。
三、测量残余暴露:比例必须连同探测设计一起读#
服务端能改,客户端不能。Cloudflare 无法直接测试访客是否仍信任弱密钥,于是用挑战页发两个探测连接:一个指向装了 eMudhra 签名证书的端点,一个指向正常签名证书的对照端点,记录探测是否成功。一周内约 5000 万次探测,结论是:较新的现代浏览器大多已修补,机器人与旧浏览器没有;嵌入式浏览器如 Android WebView 仍有 30%–40% 接受;按网络(ASN)看,大型网络中超过一半探测仍接受被攻破的链,周末有一些修补,之后趋势基本持平。
但这些百分比不能脱离观测设计单独引用。原文自己列出了若干混杂因素,值得当作核对清单:
| 因素 | 对读数的影响 |
|---|---|
| 挑战页流量高度偏斜,含大量未确认机器人 | 比例不代表全体用户,只代表这一类流量 |
| 只有执行 JavaScript 的客户端会发探测 | 无 JS 客户端、部分嵌入式环境完全不在样本内 |
| 10 月 23 日 15:30 对照端点也改为提供 eMudhra 证书(去掉 SCT) | 对照基线变化,前后不可直接比较 |
| 10 月 23 日 16:30 挑战平台因无关问题回滚,探测 10 月 27 日 10:00 才恢复 | 出现监控缺口,缺口内的“修补”不可解读 |
| 10 月 27 日 16:37 补发 G3 交叉签名、两端点移除 SCT;16:49 对照端点改链到 AAA 根 | 接受率变化可能来自链配置,而非客户端修补 |
| 10 月 27 日 18:18 探测比例从 1% 提到 10% | 样本结构改变,绝对量上升不等于趋势 |
最值得记住的是一个反向案例:10 月 29 日 18:00 UTC 左右,Cloudflare 上线了一项检测,捕获大量伪装成 macOS 上 Chrome 150–154 的机器人流量。在顶层图上,这看起来像是修补进度跳升,实际是流量分类发生变化——同一批 user agent 在带机器人信号的图里出现了对应的接受率上升。真正与修补一致的信号,是 Linux 上 Chrome 150–154 的接受率持续下降;原文称这类证据是提示性的,而非结论性的。
结论很朴素:报告“残余暴露下降”之前,先确认下降来自客户端行为,而不是来自端点配置、样本比例或分类规则。
四、滥用证据:时间线往往比百分比更能说明紧迫性#
Cloudflare 在 Pingora 中加入日志,用来记录由弱密钥签名的证书,10 月 21 日完成部署。一周后约 22,000 次握手尝试:约三分之二是对测试站点(如 emudhra.we-have-a-problem.com)的抓取;剩余三分之一几乎都指向看起来是源站自己用弱中间证书配置的证书。所有配置了证书验证的握手都被拒绝。
其中约 160 次值得单独看:证书的 Subject Alternative Name(SAN,主题备用名称)指向其他组织的域名,与握手请求的 Server Name Indication(SNI,服务器名称指示)无关,部分涉及消费级 IoT 设备域名;这些证书在密钥泄露之后签发,有的有效期超过两年,长于任何公共 CA 可签发的期限。但它们看起来像服务器自身的默认证书,域名不匹配本来就会导致主机名验证失败,且同一证书出现在多个位置,说明来自服务器本身而非单条网络路径。
因此可以下的判断是有限的:有伪造,没有证据表明弱密钥被用于拦截 Cloudflare 的连接;一张伪造证书的时间戳是 10 月 20 日 18:19 UTC,在 Mozilla 的 bug 报告公开后不到一小时。这不能排除精心定向的拦截——那要依赖系统失陷的常规间接信号,材料称目前未见此类信号。
五、一份可复核的核对清单#
- 写清对象与基期:哪个信任库、哪个版本、统计窗口起止。没有基期的“下降”无法比较。
- 吊销侧核签名者:CRL/OCSP 的签发者、序列号、生效时间;确认不是由已泄露的弱密钥签名。
- 替换侧要证据不要通知:每个信任点给出“已拒绝”的可出示证据,而不是“已发邮件”。
- 暴露侧埋点:统计被拒绝的握手,并区分测试流量、源站自签流量、第三方域名流量。
- 固定探测口径:端点证书链、SCT、交叉签名、探测比例一旦变更,记入时间线,前后数据不混算。
- 归因分开报告:把“客户端修补”与“流量分类变化”分成两个结论,不合并成一条上升曲线。
- 写明未覆盖范围:不执行 JS 的客户端、无探测通道的设备,应直接标为盲区,而不是默认安全。
六、边界与待核实#
本次材料只提供 Cloudflare 一侧的观测与处置,因此以下问题保持开放:eMudhra 未公开密钥生成脚本,审计方与交叉签名方在其中扮演的角色尚未澄清;各浏览器、操作系统与加密库的具体版本修补状态、各信任库的当前吊销状态,本次材料未提供,需另行核实;本文未运行任何代码,文中示例仅作类别示意。
回到标题:这八把弱密钥之所以值得当作追踪样本,不是因为数值荒唐,而是因为它把吊销、替换、暴露三条进度指标压在同一条时间线上。当口径不一致时,最容易发生的错误不是漏掉某个系统,而是把一条改变了定义的曲线,读成了修补已经完成。
常见问题(FAQ)
CRL 能下载到,就代表吊销已经生效吗?
一个“仍有 X% 客户端接受弱证书”的数字能代表全体用户吗?
伪造证书出现,是否等于已经发生拦截?
参考来源
以上为本文写作时的参考资料,引用观点以原文为准。