第 5 篇:TLS 生态的三个攻击面——从代码到信任根
标签:
#TLS#网络安全#Heartbleed#BEAST#POODLE#PKI#DigiNotar
TLS 不只是一段加密代码
很多人以为 TLS 安全性 = 实现里有没有 bug。其实TLS 是一个多层协议栈,攻击者可以从三个不同的层面攻破它:
| 层级 | 攻击目标 | 修复方式 |
|---|---|---|
| 第一层·实现层 | TLS 代码本身 | 静态分析 + 模糊测试 + 快速补丁 |
| 第二层·协议层 | TLS 协议设计 | 协议升级 + 全生态同步 |
| 第三层·信任根层 | 证书签发 / CA 体系 | CT 透明日志 + 短证书 + CAA |
今天这一篇,我们从内到外走一遍——近 15 年里,三个层面各自的"代表灾难"。
第一层:实现层攻击——协议没问题,代码写错了
协议标准 RFC 写得清清楚楚,但落到代码里,工程师还是会写出 bug。这一类攻击最常见,也最容易被原书作者列为"实现问题"独立成章。
2014 · Heartbleed —— 一次简单的 memcpy 错误
事件:OpenSSL 的 Heartbeat 扩展(RFC 6520)允许客户端发一个"心跳"请求,告诉服务器"我还在线",服务器回复相同数据。
OpenSSL 的实现里,请求结构里有一个"载荷长度"字段,但代码直接信任了它——没有校验"长度字段"是否真的和实际内存里能读到的数据量匹配。
于是攻击者发一个心跳请求,把长度字段写成 65535,服务器就老老实实把自己内存里的 64KB 数据返回给攻击者——其中可能包括:
- 用户的私钥
- 其它用户刚发过的密码、cookie
- 这次连接的主密钥(能让攻击者解密这次 TLS 流)
影响:当年的研究估计,17% 的 HTTPS 服务器受影响——大约 50 万台。事发后两个月内,几乎所有大型互联网公司都做了大规模密钥替换。
修复:升级到 OpenSSL 1.0.1g(修复的同时引入OPENSSL_NO_HEARTBEATS编译选项默认关闭)。
血泪教训:"用户输入的边界值"是 C 语言实现的最大陷阱。任何读取外部数据时,必须用"零拷贝 / 长度自描述"的现代设计——而不是相信字段说多长就是多长。
2014 · Apple goto fail —— 一行多余的代码
事件:iOS 6.0 / macOS 10.9 的 Secure Transport 在校验 TLS 服务器证书时,源代码里多了一个goto fail;语句:
if((err=SSLHashSHA1.update(...))!=0)gotofail;if((err=SSLHashSHA1.final(...))!=0)gotofail;// 这里原本应该结束 if,但作者复制粘贴时多写了一个gotofail;err=sslRawVerify(...);fail:// 走这里时 err 仍然是 0结果:不管证书是否合法,SSLVerifySignedServerKeyExchange永远返回 0(成功)。整个 iOS 6 时代的 HTTPS 验证形同虚设——任何一个自签名证书都能通过。
影响:iOS 6.0 - 6.1.3、macOS 10.9 - 10.9.2 全线中招。
修复:iOS 6.1.3 / 10.9.2 紧急更新;Apple 之后引入BoringSSL作为下游实现。
关键洞察:复制粘贴 bug——goto fail;看起来无害,但放在 C 代码里就成了跳过所有后续验证的"直达电梯"。编译器不会警告。代码审查没发现。最后是被外部安全研究者 (Adam Langley 等) 在源码对比中偶然发现。
2014 · CCS Injection —— 消息顺序没检查
事件:OpenSSL 的状态机在处理ChangeCipherSpec(CCS)消息时,没有验证这条消息在握手流程里的位置。
正常顺序:ClientHello → ServerHello → ServerCertificate → ServerKeyExchange → ServerHelloDone → ClientKeyExchange → CCS → Finished
攻击者发的顺序:ClientHello → ServerHello → ServerCCS → ServerFinished → ...
服务器看到 CCS 时就立刻切到新密钥状态,但客户端根本还没准备好——后续的密钥派生会基于错误的状态进行。
影响:当年 ~ 11% 的 HTTPS 服务器受影响。攻击者可让加密流变成明文。
修复:OpenSSL 2014 年 6 月补丁;所有主流 TLS 实现都加了CCS 必须在 ClientKeyExchange 之后的顺序检查。
关键洞察:状态机是协议实现里最复杂的部分——任何"消息处理"代码都必须先校验"这条消息是否在当前允许的转换里",否则就被降级到错误状态。
2013 · Lucky 13(实现层视角)
事件:Nadhem AlFardan 和 Kenny Paterson 在 2013 年发现,CBC 模式的 TLS 解密过程会根据 padding 是否合法产生不同的时延——大约差 13 个时钟周期(这是名字来源)。
但攻击的实现层视角是:当时所有主流 TLS 实现都没有用恒定时间解密——OpenSSL 的代码里有大量if (padding_correct)之类的分支,攻击者可以通过网络时延差恢复明文。
实现层修复:
- OpenSSL 引入恒定时间解密(用位运算代替 if-else)
- 性能下降 ~ 5%
- 后来 GCM 模式普及直接淘汰了 CBC
下一节在第二层会再讲一次 Lucky 13——那时候的视角是"为什么 CBC 模式的设计本身就让这种时序泄露不可避免"。
2017 · ROBOT(实现层视角)
事件:Bleichenbacher 1998 年的 RSA PKCS#1 v1.5 padding oracle 攻击,在 2017 年再次复活——这次是通过观察 TLS 服务器对错误 RSA 密文的响应差异。
攻击者发了 100 万次精心构造的 RSA 密文,观察服务器返回的是decrypt_error还是bad_record_mac,两种响应在某些实现里有几十微秒的时延差——足够区分。
实现层修复:
- OpenSSL、BoringSSL、CyaSSL 在 2017 年底统一做了恒定时间错误响应
- 把所有错误码映射到同一个恒定响应
下一节在第二层会再讲 ROBOT——那时候的视角是"RSA PKCS#1 v1.5 这个协议设计本身就有结构性漏洞"。
2014 · POODLE(实现层视角)
事件:Google 在 2014 年发现SSLv3 + CBC 模式下,攻击者可以通过 padding oracle 逐字节恢复明文。
实现层视角:
- 浏览器厂商在 2014 年底直接禁用 SSLv3
- 服务器软件(Apache、Nginx、IIS)也默认关闭 SSLv3
- 但很多企业内部系统(旧 OA、旧 ERP)一直拖到 2018 年才彻底禁用——这一段过渡期留下了很多攻击窗口
下一节在第二层会再讲 POODLE——那时候的视角是"为什么 SSLv3 的协议设计让这种攻击根本不可修补"。
2015 · SMACK —— TLS 状态机系列 bug
事件:2015 年,伦敦大学学院的研究者用TLS-Attack-Toolkit(一个故意发非法 TLS 消息序列的工具)扫描了 9 个主流 TLS 实现:
| 实现 | 发现的 bug |
|---|---|
| OpenSSL | 早期版本有多条 |
| NSS(Mozilla) | 3 条 |
| CyaSSL(wolfSSL) | 4 条 |
| GnuTLS | 5 条 |
| PolarSSL(mbed TLS) | 6 条 |
| MatrixSSL | 4 条 |
| … | … |
几乎所有主流实现都有"状态机转换错误"问题——只是程度不同。
修复:
- 各大实现都做了状态机重构
- 引入模糊测试(fuzzing)在 CI 中持续运行
- 部分实现引入形式化验证(如 AWS s2n 用 ProVerif)
2010s 之后:新一代 TLS 实现
旧的 OpenSSL 危机直接催生了新一代实现:
| 实现 | 出现时间 | 主要特点 |
|---|---|---|
| LibreSSL | 2014(OpenBSD fork) | 清理 OpenSSL 历史包袱,移除冗余代码 |
| BoringSSL | 2014(Google fork) | TLS 1.3 早期试验场 + Android / Chrome 默认 |
| s2n | 2014(AWS) | 仅 ~ 5000 行代码 + ProVerif 形式化验证 |
| Rustls | 2020(Rust 重写) | 内存安全 + 进入 curl 7.88 作为 TLS 后端 |
| PicoTLS | 2017 | ARM mbed TLS 的精简版,IoT 友好 |
第一层的整体观察:实现层 bug 永远会有,但通过形式化验证 + 持续 fuzzing + 自动化测试,可以把"灾难级"事件的概率压到极低。
第二层:协议层攻击——设计本身有问题
即使代码完美正确,协议设计也可能让攻击者有机可乘。这一类攻击一旦被公开,整个生态都要动——TLS 1.2、1.3 几次重大改版,几乎都是被这类攻击逼出来的。
这一层是原书第 7 章的核心内容,作者花了近 50 页讲。
2009 · 不安全重新协商 —— TLS 协议的"身份错位"
事件:研究者 Marsh Ray 和 Steve Dispensa 在 2009 年 8 月发现了一个让安全社区震动的问题:TLS 重新协商(renegotiation)时,新旧两次握手之间没有绑定关系。
具体来说:
- 客户端发起新握手时,服务器不会验证新握手的对端是不是旧握手的同一对端
- 即使有加密 + 完整性校验,TLS 也无法保证"重新协商之后,还是同一个客户端"
怎么攻击(三步 MITM):
- 攻击者拦截受害者 → 服务器的 TCP 连接
- 攻击者先自己向服务器发一个 TLS 握手,里面包含攻击负载(比如一个 HTTP GET)
- 攻击者把这个 TCP 连接转发给受害者,受害者的 TLS 握手被服务器理解为"重新协商"
- 服务器把攻击者的请求和受害者的请求拼到一起处理
对 HTTP 的攻击向量(原书 7.1.3 详细列出了 4 种):
- 任意 GET 请求:用受害者的 cookie 访问任意 URL
- 凭据窃取(Anil Kurmus 改进):Twitter 案例——攻击者把受害者的 Authorization 头作为 Twitter 消息内容发出去,凭据就这样泄露
- 用户重定向:用 307 重定向把请求转到攻击者控制的服务器
- XSS:通过 TRACE 方法注入 HTML
对其它协议的影响:
- SMTP:原书分析了 Postfix——结论是 SMTP 协议本身的命令-响应结构让攻击难以展开
- FTPS:Alun Jones 发现某些 FTP 服务器有文件传输实现问题,可能受攻击
修复:RFC 5746(2010 年 2 月)——在 TLS 握手里加了Renegotiation Info扩展,把旧握手的client_random绑定进新握手。所有现代实现都已经支持。
教训:"一段 TLS 连接对应一个稳定身份"是协议的核心假设——一旦允许中途切换身份(重新协商),必须显式证明新旧身份是同一个。任何带状态切换的协议都得重新审视这个假设。
2011 · BEAST —— CBC 的 IV 链式灾难
事件:Juliano Rizzo 和 Thai Duong 在 2011 年的 ekoparty 安全大会上演示了 BEAST(Browser Exploit Against SSL/TLS)——对 TLS 1.0 + CBC 模式的实际攻击。
原理(极简版):
- TLS 1.0 的 CBC 模式用前一段密文作为下一段的 IV
- 攻击者通过"在密文里塞一个明文块"的方式,让自己控制的字节成为下一段的 IV
- 配合 Java applet 这类能强制发送"已知明文"载荷的工具,逐字节恢复 session cookie
修复:
- TLS 1.1(2006)已经把 IV 改成显式随机生成
- 但很多服务器还在跑 TLS 1.0——浏览器在 2011 年开始默认启用 TLS 1.1/1.2
- OpenSSL 引入1/n-1 split 补丁(每段都换 IV)
教训:"用前一段密文当 IV"这个方案在 2002 年的 BEAST paper 之前就已经被理论攻破——但实际部署一直没动。等到有人公开做了端到端 PoC,整个生态才被动跟进。这是 TLS 部署的真实节奏:标准是一回事,生态动起来是另一回事。
2012 · CRIME —— 压缩的副作用
事件:Juliano Rizzo 和 Thai Duong 再次出击,这次用TLS 层压缩作为攻击面:
- TLS 支持
DEFLATE压缩(TLS_DEFLATE) - DEFLATE 用 LZ77 算法——相同字符串会压缩成更短的输出
- 攻击者控制客户端请求的一部分字节(比如路径、Cookie 字段)
- 攻击者通过观察压缩后密文长度的变化,反推请求里有没有命中某些 token
原理:DEFLATE 对"已知 token + 未知 token"压缩时,如果能命中,输出就更短。长度本身就是侧信道。
修复:
- 浏览器厂商在 2012 年底全面禁用 TLS 压缩
- SSL Labs 的客户端测试里 TLS 压缩支持度一夜间归零
教训:压缩是数据建模的好工具,但也是侧信道的放大器——任何"输入和输出大小可观察"的加密协议,都要警惕基于长度的攻击。
2013 · Lucky 13(协议层视角)
事件:Nadhem AlFardan 和 Kenny Paterson 在 2013 年发现,即使 TLS 1.1/1.2 的 IV 不再用前一段密文,CBC 模式的 padding 解密时延依然可以泄露 padding 是否正确。
协议层视角——为什么这个问题从根本上难以修补:
- CBC 模式的 padding必须在解密后立刻检查才能丢弃
- 这个"检查"在硬件上必然涉及分支——CPU 的分支预测会让错误 padding 和正确 padding 的处理耗时不同
- 13 个时钟周期的时延差(因此得名"Lucky 13")
协议层修复:实际上没有干净的协议层修复。唯一的彻底解决方案是放弃 CBC 模式——TLS 1.3 直接砍掉了 CBC。
上一节在第一层讲了 Lucky 13 的实现层视角——那次讲的是"实现需要做恒定时间解密"。这两层的修复配合使用才能彻底防御:协议层放弃 CBC(CBC 不再是合法选项)+ 实现层在 GCM 普及前对 CBC 做恒定时间改造。
2013 · RC4 偏差系列攻击
事件:AlFardan 等人在 2013 年也研究了 RC4 密钥流的统计偏差:
- RC4 的密钥流在第一个字节就有 1/256 的偏向(也就是说,正确值出现的概率是 1/256,而其它值出现的概率略低)
- 多个偏移位置的偏差累加起来形成了可利用的信号
- 在 13×2^27 次握手里恢复会话 cookie 中的少数字节完全可行
修复:
- 浏览器在 2013 年起逐步禁用 RC4
- 到 2015 年所有主流浏览器都不再接受 RC4 套件
- TLS 1.3 直接把 RC4 从合法密码列表里删掉
关键洞察:一个有理论缺陷但没有公开 PoC 的密码学原语,比有 PoC 的更危险——因为生态不会主动下架它。RC4 的统计偏差从 1995 年就开始被讨论,RSA 实验室 2001 年的"真实世界用 RC4 没问题"结论被反复打脸——一直坚持到 BEAST / Lucky 13 之后,RC4 才真正退役。
2013 · BREACH —— HTTP 压缩的"复活"
事件:CRIME 禁了 TLS 层压缩,但 HTTP 层(gzip / deflate)的压缩没人管:
- TIME 攻击(2013):用 JavaScript 多次测量响应长度变化,反推服务器响应里的 CSRF token
- BREACH(2013, Segfaultcrew):把 TIME 推广到几乎所有 HTTP 响应体,可恢复任意 secret
修复:
- 浏览器禁用 HTTP 响应压缩(保留请求压缩)
- 部分公司通过在响应里加随机字节、或者禁用对敏感字段的压缩来对抗
- 今天的标准做法:用
Content-Security-Policy: no-referer、SameSite Cookie、把敏感 token 放到加密的路径里
关键洞察:侧信道是协议层面的事,不是"加密对不对"——加密方案正确不等于抗侧信道。
2014 · 三次握手攻击(3SHAKE)
事件:Jager 等人在 2014 年发现:客户端发起重连(resumption)时,TLS 不携带原始主密钥或client_random——只在 ClientHello 里给出新的client_random。
攻击流程:
- 拦截一次 TLS 连接
- 在中途把它"重连",把
client_random替换成"攻击者 + 受害者混合"的会话 - 服务器以为是同一个人持续连接,实际是两个不同身份
修复:
- RFC 7627(2015):resumption 必须绑回原始
client_random - TLS 1.3直接废弃 resumption 的这一用法,改用 PSK +
ticket_identifier
关键洞察:会话恢复(session resumption)绕过了完整握手的所有验证——理论上必须证明新会话是旧会话的合法延续。
2014 · POODLE(协议层视角)
事件:Google 在 2014 年披露 POODLE(Padding Oracle On Downgraded Legacy Encryption)。
协议层视角——为什么这个攻击不可修补:
- SSLv3 没有任何 padding 完整性检查
- 只有 CBC 模式自己有 padding,但最后一个字节的 1/256 命中概率让 padding oracle 完全可行
- SSLv3 没有 HMAC,所以定位不到"padding 错误"是否加密后被改过——攻击者可以在中间篡改密文
唯一的协议层修复:放弃 SSLv3。
实际部署影响:
- 浏览器、服务器在 2014-2015 年完全禁用 SSLv3
- TLS 1.0/1.1 在 2018-2020 年也被逐步禁用
- 但很多企业内部老旧系统一直坚持到 2018 年才彻底禁用 SSLv3——这一段过渡期留下了攻击窗口
上一节在第一层讲了 POODLE 的实现层视角——那次讲的是"浏览器和服务器怎么紧急部署禁用"。协议层的根本是"SSLv3 协议设计有先天缺陷"。
2013 · Bullrun —— NSA 后门计划
事件:2013 年 9 月,Edward Snowden 泄露的 NSA 内部文件显示,NSA 在 1996 年开始了一项名为Bullrun的秘密计划:
- Dual_EC_DRBG:NIST SP 800-90A 中的随机数生成标准,被植入了 NSA 掌握的"陷门"。攻击者只要知道这个陷门,就能从随机数输出恢复出内部状态,进而预测后续所有密钥。
- RSA BSAFE:被 NSA 收购后植入默认参数的密码学库。默认
e = 65537在某些版本里被悄悄换成 NSA 选定的弱指数。 - SSL/TLS 加速芯片:被植入的硬件后门,能让加密流在不解密的情况下被"旁路"读取。
影响:
- OpenSSL等主流实现都曾经用过 Dual_EC_DRBG 作为默认随机数(直到 2014 年才完全移除)
- 影响范围是整个行业的密码学基础设施
- 多年以后,Johns Hopkins 的研究团队才正式发表论文证明 Dual_EC_DRBG 确实存在陷门
修复:
- NIST 2014 年撤销 SP 800-90A 中的 Dual_EC_DRBG
- RSA 在 2014 年停止销售 BSAFE
- 行业转向CTR-DRBG / Hash-DRBG / AES-CTR-DRBG等更简单的随机数生成器
- 新标准用"透明化"对抗:NIST 2017 年的"轻量级密码学标准化"流程公开了所有候选算法的内部结构
关键洞察:密码学基础设施的信任不能建立在单一组织上。这件事之后,社区开始推动:
- 多源随机数混合(Linux 内核的
getrandom()用多个熵源) - 公开算法竞赛(NIST 后来的 SHA-3、CAESAR 竞赛都更强调公开性)
- 形式化验证(不只相信实现正确,还要证明)
2016 · DROWN —— 跨协议攻击
事件:DROWN(Decrypting RSA with Obsolete and Weakened eNcryption)由 Nimrod Aviram 等人在 2016 年披露:
- 攻击者扫描目标服务器是否还开着SSLv2
- 即使服务器从来不接受 SSLv2 协商,只要它支持 SSLv2 +共享 RSA 私钥,攻击者就能恢复 RSA 密钥
- 恢复出 RSA 私钥后,所有 TLS 连接的 RSA 密钥交换都被解密
影响:当年33% 的 HTTPS 服务器受影响。
修复:
- 禁用 SSLv2
- 把 RSA 密钥替换为 ECDHE 密钥交换(强制前向保密)
关键洞察:协议隔离不等于密钥隔离——只要多个协议共用一个私钥,攻击就能从最弱的协议往最强的协议跨越。
2017 · ROBOT(协议层视角)
事件:Hanno Böck 等人在 2017 年披露 ROBOT(Return Of Bleichenbacher’s Oracle Threat)。
协议层视角——为什么 19 年后还能复活:
- Bleichenbacher 在 1998 年提出的 “RSA PKCS#1 v1.5 padding oracle” 攻击,让 RSA 在 TLS 里理论上就是脆弱的
- 但 19 年来一直没人能稳定实施——直到 2017 年的研究找到了可重现的实施路径
原理:
- 攻击者发 100 万次精心构造的 RSA 密文
- 观察服务器对每个密文的响应——错误码和时延在某些实现里有差异
- 通过这些差异逐步恢复 RSA 私钥
影响:当年 ~ 27% 的 HTTPS 服务器受影响。
协议层修复:
- 强制改用RSA-PSS或者完全切到ECDHE密钥交换
- 关闭 RSA 密钥交换(TLS 1.3 直接砍掉 RSA 密钥交换)
关键洞察:协议层面的 padding oracle 这类结构性缺陷,只有"彻底换算法"才能根治。
上一节在第一层讲了 ROBOT 的实现层视角——那次讲的是"实现需要做恒定时间错误响应"。协议层修复才是根治。
2020 · Raccoon —— DH 时序攻击
事件:Raccoon(2020, Merget et al.)—— DH 和 ECDHE 的密钥交换在某些实现里有恒定时间问题:
- 攻击者通过测量服务器响应时间
- 在大量请求中逐步恢复 DH 共享密钥
- 重点是某些实现里,DH 共享密钥的特定低位会泄露到响应时间
修复:
- 所有主流实现(OpenSSL、BoringSSL)在 2020 年做了恒定时间改造
- Raccoon 影响的是实现层但触发原因是协议层——边界案例
关键洞察:"实现层 vs 协议层"的边界是模糊的——Raccoon 是协议允许的恒定时间问题,但实际触发要看实现。
2018+ · TLS 1.3 的 0-RTT 重放
事件:TLS 1.3 引入0-RTT 模式——客户端可以在第一个 TCP 包里就发送加密请求,完全跳过握手。
代价是重放风险:
- 0-RTT 模式使用 PSK(预共享密钥)导出的"早期数据密钥"
- 这段密钥是静态的:同一个 PSK 在多个会话里复用
- 攻击者抓到一个 0-RTT 请求,可以重发一次
如果服务器没有单次使用标记或者强制 freshness 检查,可能导致:
- 重复充值
- 重复下订单
- 重复发邮件
修复:
- 浏览器默认对所有 0-RTT 请求加幂等性键(
Idempotency-Key) - 后端应该把 0-RTT 操作设计成幂等
- 不少 CDN(Cloudflare)允许配置"对路径禁用 0-RTT"
- 或者直接关闭 0-RTT:线上购物、支付、密码修改等绝不接受 0-RTT
关键洞察:性能优化的代价经常是"安全模型变了"——0-RTT 用"轻量握手"换取性能,但牺牲了"每个请求唯一一次"的保证。
协议层攻击为什么难根治
把这一层的事件放一起看:
| 类型 | 代表 | 协议层修复 |
|---|---|---|
| 握手结构 | 不安全重新协商、三次握手 | 协议扩展 + 强制绑定 client_random |
| 加密模式侧信道 | BEAST、Lucky 13、RC4 偏差 | 协议升级 + 弃用 CBC/RC4 |
| 压缩侧信道 | CRIME、BREACH | 协议层禁压缩 + 浏览器禁 HTTP 响应压缩 |
| Padding oracle | POODLE、ROBOT | 整体放弃旧协议/旧算法 |
| 跨协议泄露 | DROWN | 关闭共享私钥的旧协议 |
| 时序 | Raccoon | 协议升级(TLS 1.3)+ 恒定时间实现 |
| 重放 | 0-RTT | 强制幂等性 + 单次使用标记 |
规律:协议层面的攻击一旦发现,唯一稳定的修复是协议升级 + 实现恒定时间。这要求整个生态同步升级——而现实中生态往往需要"攻击公开 + 多年过渡"才会动。
第三层:信任根层攻击——CA 闯的祸
TLS 信任链的根是CA(证书颁发机构)。如果 CA 被攻破——或者 CA 主动签发恶意证书——整个 TLS 信任体系就崩塌了。
这一层是原书第 4 章的核心内容。作者把"PKI 攻击"单独列为一章,是因为这类攻击的影响远超协议本身:一张假证书就能让整个互联网的 HTTPS 形同虚设。
这里只回顾最近 15 年的事件——更早的(VeriSign 2001、Thawte 2008、RapidSSL MD5 碰撞 2008)属于上一代 PKI 历史,今天的生态已经没有同等可比性。
2011 · Comodo 代理商被入侵
事件:2011 年 3 月,一名伊朗攻击者入侵了 Comodo 的多个代理商账号,签发了9 张高价值证书:
login.live.commail.google.comwww.google.comlogin.yahoo.com- 等
这些证书只签发了几小时——Comodo 几小时后察觉并吊销,但浏览器厂商仍然需要做紧急信任更新。
影响:
- 这是第一次让"CA 攻击"从理论威胁变成实际事故
- 各大浏览器开始认真讨论 PKI 防御机制
2011 · DigiNotar 灾难
事件:荷兰 CADigiNotar在 2011 年 7 月被攻破,至少 531 张假证书被签发,包括*.google.com这种通配符证书——相当于拿到了 Google 全站的"钥匙"。
攻击者利用了 DigiNotar 的内部系统漏洞,先签发伊朗用户的假证书(用于监控),最后扩大到 Google、Mozilla、WordPress.org 等。
影响:
- DigiNotar 母公司VASCO Data Security在 2011 年第三季度直接破产
- Mozilla、Microsoft、Google、Apple同时宣布完全撤销对 DigiNotar 的信任
- 这是 PKI 历史上最严重的单一事件——第一次让一家主流 CA 整体消失
修复:
- Mozilla 推出OneCRL / CRLite来集中撤销列表
- Chrome 引入Certificate Transparency(2013 起逐步强制)
2015-2017 · Symantec「证书门」
事件:安全研究者在 2015 年发现 Symantec 的证书签发流程有多个重大违规:
- 错误签发了
google.com和O=test等测试证书 - 没有按 CA/B Forum 要求做完整的域名所有权校验
- 后续调查显示至少 30000 张证书违规
整个调查持续到 2017 年,最终 Mozilla 给出最后通牒:必须迁移到 DigiCert。
影响:
- 2018 年起,所有浏览器不再信任 Symantec 品牌证书
- 客户必须重新申请证书(一次大规模迁移)
- 推动了CA 审计流程的强化——所有公共 CA 必须在 WebTrust/ETSI 审计下持续接受检查
2016-2017 · WoSign / StartCom 倒签
事件:Mozilla 在 2016 年披露,WoSign(一家中国 CA)被发现有以下问题:
- 给一张SHA-1 证书倒签日期(让它"看起来"是 2016 年签发的,但实际签名算法是 2014 年的 SHA-1)
- 收购 StartCom 后隐瞒收购事实,继续以 StartCom 品牌签发证书
- 同一公钥对应多个证书(违反 CA/B Forum 规则)
影响:
- Mozilla、Apple、Google 在 2017 年完全撤销对 WoSign 和 StartCom 的信任
- WoSign 后来彻底退出 CA 业务
- 推动了 “公钥重用” 检测——浏览器现在会拒绝同一公钥对应不同证书
2018 · Let’s Encrypt 数据库 dump
事件:2018 年 1 月,Let’s Encrypt 报告内部数据库被外部工具错误暴露约 1580 万邮箱地址 + 部分 API key。
虽然没有直接签发假证书,但这是免费 CA 也必须严肃对待的事件:
- 推动了 ACME 协议的进一步强化
- 没有 CA 可以例外——即使是 Let’s Encrypt 这种"模范生",合规要求依然严苛
2019 · Trustico 证书倒卖门
事件:2019 年初,证书经销商Trustico把客户从 Symantec 迁移到 DigiCert 时,一次性向 DigiCert 发送了 23628 张证书的吊销请求——很多证书客户根本没要求吊销。
DigiCert 在几小时内强制吊销全部证书——很多企业的 HTTPS 业务当场中断。
影响:
- 揭示了 CA 生态里经销商 / 客户 / CA 三方关系的脆弱性
- 推动了 DigiCert 引入经销商操作的二次确认机制
2019-2020 · DarkMatter 想成为根 CA 被拒
事件:阿联酋公司DarkMatter想申请进入 Firefox / Chrome 的根 CA 信任库。
问题是:DarkMatter 的主要业务是为阿联酋政府做网络监控——包括之前的 Project Raven(监控记者、人权活动家)。
结果:
- Mozilla 在 2019 年拒绝DarkMatter 的申请
- Apple 也拒绝
- “CA 不只是技术中立机构,它必须代表公共信任”——这是 PKI 治理的重要转折点
2020 · TrustCor 系统性问题
事件:Mozilla 在 2020 年 11 月披露,TrustCor(一家在巴拿马注册的 CA)有以下系统性问题:
- 母公司做间谍软件业务(MSG 数据泄露事件)
- TrustCor CA 的子私钥被发现出现在GPS 模组固件里——意味着有人可能在不知情下被签发证书
结果:
- Mozilla / Microsoft 在 2020 年底完全撤销对 TrustCor 的信任
2021 · Sectigo 漏签内部名称证书
事件:Sectigo 在 2021 年被发现错误签发了.internal名称的证书——这种保留给 RFC 6762 的内部名称不应该出现在公网证书里。
影响:
- 这类证书不能被外部验证,反而成了**“假证书” 的攻击向量**
- Mozilla 推动 CA 必须在签发前强制检查内部名称列表
2022 · DigiCert 错签 15.7 万张证书
事件:DigiCert 在 2022 年 7 月披露,由于证书签发系统配置错误,在过去 6 周里错签了157000 张证书——很多证书包含错误的域名信息。
影响:
- 这是Symantec「证书门」以来最大单一 CA 治理事件
- DigiCert 必须主动吊销这些证书并重新签发
- 推动了CA 必须在签发前做"自检 + 域名校验双重确认"
2022-2024 · 「47 天证书」革命
事件:Apple 和 Google 在 2022 年单方面宣布:
- iOS / macOS 上的证书最长有效期从 398 天降到90 天
- Chrome 在 2024 年开始强制90 天 + 自动化的证书
注意——这些决定绕过了 CA/B Forum——CA/B Forum 还在讨论,没有正式通过。
结果:
- CA/B Forum 在压力下通过了47 天证书提案(部分讨论甚至包括 7 天证书)
- ACME 自动化签发(Let’s Encrypt 已经在用)成为唯一现实选择
- 手工管理证书很快会成为历史
2023-2024 · CT 2.0 多证人体系
事件:Certificate Transparency(CT)从 2018 年的"Chrome 单日志"扩展为多日志 + 多证人体系:
- Chrome 在 2023 年起拒信没有 SCT(Signed Certificate Timestamp)的公网证书
- SCT 必须由多个独立 CT 日志联合签名
- 任何一张证书的签发都会永久公开
关键洞察:信任不能建立在单一组织的"会按规矩办事"上——CT 用"公开透明"对抗"内部腐败 / 失误"。
2024 · ML-KEM 后量子标准
事件:NIST 在 2024 年 8 月正式发布FIPS 203——基于 CRYSTALS-Kyber 的后量子密钥封装机制ML-KEM。
主流浏览器(Chrome 124+、Firefox、Safari)已经开始混合密钥实验——在传统 ECDHE 之外加入 ML-KEM,确保即使量子计算机真正出现,过去的 TLS 连接也不会被解密。
影响:
- TLS 1.3 的密钥交换层将在未来几年加入 ML-KEM 作为合法选项
- 现有 ECDHE 仍然保留(向后兼容)
- 长生命周期数据(医疗记录、机密文件)从 2025 年起建议直接用 ML-KEM 加密
PKI 生态的修复方向
把这一层的事件放一起看,攻击模式已经从"单点灾难"演化为"系统性问题":
| 时期 | 主要威胁 | 防御机制 |
|---|---|---|
| 2010-2014 | CA 被入侵、单点灾难 | CRL / OCSP |
| 2015-2018 | CA 内部违规、治理失效 | WebTrust 强化、浏览器主导审计 |
| 2019-2022 | 经销商 / 地缘政治问题 | CT 多日志、品牌信任精细化 |
| 2023-2024+ | 系统性自动化压力 | 90/47 天证书 + ACME + ML-KEM |
关键洞察:PKI 的核心挑战不是技术,而是治理——技术修复(CT、短证书)只能降低"CA 失败"的概率,不能完全消除。
三个攻击面,对应三种防御
| 层级 | 攻击特征 | 防御思路 | 现实工具 |
|---|---|---|---|
| 第一层·实现层 | 边界检查、状态机、内存安全 | 形式化验证 + fuzzing + 静态分析 | AFL、libFuzzer、ProVerif、Rust |
| 第二层·协议层 | 设计假设、侧信道、降级 | 协议升级 + 全生态同步 + 弃用老算法 | TLS 1.3、AEAD 模式、GCM/ChaCha20-Poly1305 |
| 第三层·信任根层 | CA 被攻破、CA 违规、系统性失效 | CT 透明 + 短证书 + CAA + 替代信任模型 | Let’s Encrypt、CT 监控、SCT 要求 |
三个层级在现实中往往联动**:**
- Heartbleed + POODLE(实现 + 协议)
- DigiNotar + 短证书(信任根 + 协议层)
- ROBOT + RSA 弃用(实现 + 协议)
这就是为什么"装上 HTTPS 就完事"是错觉——真正的 HTTPS 安全是三层协同的产物。
给开发者的三条建议
① 用 SSL Labs + testssl.sh 跑一次真实审计
# 30 秒内拿到全栈报告testssl.sh--colorhttps://your-site.com报告会同时指出三个层级的问题:
- 协议层(SSL 3.0 支持、TLS 1.0/1.1 支持)
- 实现层(Heartbleed、CCS、ROBOT 检查)
- 信任根层(证书链完整性、SCT、CRL/OCSP)
② 配置 TLS 1.3 + 现代密码套件
ssl_protocols TLSv1.3 TLSv1.2; # 不再支持 1.0/1.1 ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305; ssl_early_data off; # 默认就是 off;但务必确认没设成 on如果你确实需要 0-RTT 来优化 TTFB——所有接收 0-RTT 的端点都要设计成幂等,并对"业务关键路径"主动停用。
③ 别让证书管理成为"年度大事件"
- 用 Let’s Encrypt + ACME 自动续签——Caddy 已经内置,Nginx 用 certbot
- 配置 CAA 记录——明确允许哪些 CA 签发你的域名
- 启用 CT 监控——免费监控服务如
crt.sh+ 自己的告警 - 关注 47 天证书时间表——CA/B Forum 已经通过,未来 1-2 年会强制
延伸阅读
协议层经典论文:
- TLS Renegotiation (RFC 5746)
- BEAST paper (2011)
- CRIME attack (2012)
- Lucky 13 (2013)
- POODLE (2014)
- DROWN (2016)
- ROBOT (2017)
- Raccoon (2020)
- Dual_EC_DRBG backdoor (2013)
实现层工具链:
- AFL / libFuzzer — 持续 fuzzing
- TLS-Attack-Toolkit — 状态机攻击测试
- testssl.sh — 全栈审计
- Rustls — 内存安全的现代 TLS 实现
信任根层监控:
- SSL Labs SSL Test
- crt.sh — CT 日志查询
- Mozilla OneCRL
- CA/B Forum 规则
标准与规范:
- TLS 1.3 RFC 8446
- NIST FIPS 203 — ML-KEM