Lucky 13 — 用毫秒级时间差把 TLS 加密看穿
是什么
Lucky 13 是一个TLS 协议的攻击:攻击者不破密钥、不挖算法漏洞,只反复发包,从服务器响应快了几微秒还是慢了几微秒里,一个字节一个字节把别人 HTTPS 流量里的密码、cookie 还原出来。
日常类比:你不知道保险柜密码,但每按一个数字,柜门会”咔哒”一下。错的数字咔哒慢,对的数字咔哒快——你只要安静地按几千次、记下时间,密码就出来了。
这个攻击的”幸运 13”指的是:TLS 在算消息认证码(MAC)时会先吞掉 13 字节的协议头。这个 13 字节是攻击者下手的支点。
为什么重要
不理解 Lucky 13,下面这些事都没法解释:
- 为什么 TLS 1.3(2018)直接删掉了用了 20 年的 CBC 加密模式
- 为什么现在浏览器里 HTTPS 几乎都是 AES-GCM 或 ChaCha20-Poly1305(这类叫 AEAD)
- 为什么”理论上安全”的密码协议会被一个时间测量打穿——工程实现的小细节能毁掉数学证明
- 为什么一系列以”动物”命名的攻击(BEAST / CRIME / Lucky 13 / POODLE / Heartbleed)能在 2011-2014 把 TLS 整个推倒重来
核心要点
Lucky 13 攻击的关键是 三个事实拼到一起:
-
TLS 1.0/1.1 用 MAC-then-Encrypt:先算消息认证码、把 MAC 拼到明文后面、再整体用 CBC 加密。解密时反过来:先 CBC 解密、再去 padding、再验证 MAC。
-
CBC 解密后要剥两层皮(padding + MAC),错误处理时间不一样:
- 如果 padding 格式错 → 服务器立刻报错(快)
- 如果 padding 对、MAC 错 → 服务器先算完 HMAC 再报错(慢)
- 这两种情况的时间差几微秒,但用网络可测
-
HMAC 按 64 字节分块:明文长度跨过 64 字节边界时,多算一次压缩函数,时间又抖一下。攻击者操控 padding 长度让明文落在边界两侧,对比时间。
把三件事拼起来:攻击者篡改密文里某个块,让服务器解密后得到不同的 padding 长度,测响应时间,反推那个块的最后一个字节是几。然后把它推到下一个字节、再下一个——两小时还原一个 cookie。
13 这个数字来自 TLS 协议头:5 字节记录头 + 8 字节序列号 = 13 字节。HMAC 一开始就要把这 13 字节吞进去,吞完正好让攻击的时间差对齐到容易测的位置——攻击者很”幸运”。
实践案例
案例 1:浏览器里看不见的”被淘汰”
打开 Chrome,访问任何 HTTPS 网站,按 F12 → Security 面板。你会看到类似:
Connection - secure connection settingsTLS 1.3, X25519, AES_256_GCM注意 AES_256_GCM——这是 AEAD 模式,没有 MAC-then-Encrypt 这一步,加密和认证一起做。
2013 年之前你看到的多半是 AES_128_CBC_SHA——CBC 模式 + 单独 MAC。Lucky 13 直接打这种组合。
可以用 OpenSSL 看支持的 cipher:
openssl ciphers -v 'HIGH' | grep CBC如果输出里还有 CBC 套件,那台服务器还有”被攻击的能力”。现代 Nginx / Caddy 默认配置已经把 CBC 移到列表末尾或彻底关掉。
案例 2:Lucky 13 怎么”试”出一个字节
攻击者想知道某个 CBC 块 C 解密后的最后一字节 b。流程:
- 把
C拼到一个伪造的前缀后面,发给服务器 - 服务器解密 → 看 padding → 算 HMAC → 报错
- 测响应时间
t - 攻击者把伪造前缀里的某一字节加 1 再发——这等于让服务器解密出不同的 padding 字节
- 反复试 256 种可能(一字节有 256 种值)
- 哪一种让 padding 看起来”正好合法”,时间就最特别——那就是
b
每个字节要发几千到几百万次包,统计学上才能把几微秒的差稳定地分辨出来。
案例 3:为什么 TLS 1.3 删 CBC
TLS 1.3(RFC 8446,2018)的设计直接砍掉 CBC、RC4、3DES,只留 AEAD:
AES_128_GCM_SHA256AES_256_GCM_SHA384CHACHA20_POLY1305_SHA256
AEAD 把”加密 + 认证”绑成一个原子操作。Lucky 13 类的”先解密看 padding,再验 MAC”漏洞结构上不存在了。
踩过的坑
-
“理论安全”不等于”实现安全”:CBC + HMAC 在密码学论文里有可证安全证明,但前提是”两步操作时间不可观测”。Lucky 13 证明这前提在网络上做不到。
-
修补不是真修:OpenSSL 当时打了补丁,让 padding 错误和 MAC 错误的代码路径走一样长的时间。但补丁本身又被发现有侧信道——常时间编程极难写对。
-
MAC-then-Encrypt 的设计天生危险:先认证再加密(Encrypt-then-MAC)顺序就没这问题,因为收方先验 MAC、错就直接拒,根本不会进解密路径。TLS 选错了顺序,付了 20 年代价。
-
DTLS 比 TLS 还危险:DTLS(基于 UDP 的 TLS)允许重传,攻击者可以无限次试同一个密文,效率比 TLS 高一个数量级。
适用 vs 不适用场景
适用攻击的目标(2013 年时):
- TLS 1.0 / 1.1 / 1.2 用 CBC 模式的连接
- DTLS 1.0 / 1.2
- OpenSSL / NSS / GnuTLS / PolarSSL / BouncyCastle 等所有主流实现
不适用:
- TLS 1.3(结构上无 CBC,已免疫)
- AEAD 模式(AES-GCM / ChaCha20-Poly1305)
- 启用 Encrypt-then-MAC 扩展(RFC 7366)的连接
- 网络抖动 > 时间差的场景(攻击需要稳定测量微秒级)
案例 4:常时间编程到底有多难
OpenSSL 给 Lucky 13 打的补丁,思路是:不管 padding 对不对,都跑同样多的 HMAC 压缩。看起来简单,实现却踩了一堆坑:
// 简化示意:错的写法if (padding_ok) { hmac(data, real_len);} else { hmac(data, fake_len); // 时间不一样}
// 对的写法(伪代码)hmac_blocks = compute_blocks(max_possible_len);for i in 0..hmac_blocks { sha1_compress(...); // 永远跑 max 次}但这还不够:memcpy 的长度、CPU 分支预测、内存访问模式都可能泄露。真正常时间的 HMAC 一直到 2014 年才被 OpenSSL 写对。
历史小故事(可跳过)
- 2011 BEAST(Duong-Rizzo):CBC 的 IV 可预测漏洞,把 CBC 第一刀
- 2012 CRIME:TLS 压缩侧信道
- 2013 Lucky 13(本文):CBC padding 时间侧信道
- 2014 POODLE(Möller 等):SSL 3.0 的 padding oracle,逼业界彻底淘汰 SSL 3.0
- 2014 Heartbleed(OpenSSL 内存泄露):和 Lucky 13 不同类,但同年放大了”TLS 不安全”的恐慌
- 2018 TLS 1.3 发布:清理积累 20 年的设计债
Lucky 13 是这条链子的中间一环——单独看不致命,叠加起来推倒了整个旧 TLS。
学到什么
- 侧信道是真威胁,不是论文玩具——几微秒的时间差,跨网络也能稳定测出来
- 协议设计的顺序至关重要:MAC-then-Encrypt vs Encrypt-then-MAC,一字之差差 20 年
- 常时间编程极其难:编译器、CPU 缓存、分支预测都会让”看起来对称的代码”实际不对称
- AEAD 是工程上的胜利:把”加密 + 认证”绑成一个原子操作,少一个组合就少一类漏洞
- 协议演化靠攻击驱动:BEAST → CRIME → Lucky 13 → POODLE 这条链推动了 TLS 1.3 的彻底重构
延伸阅读
- 论文 PDF:Lucky Thirteen: Breaking the TLS and DTLS Record Protocols(作者主页,含演示视频)
- TLS 1.3 RFC:RFC 8446(看 §1.2 “Major Differences from TLS 1.2”)
- 通俗讲解:Matthew Green 博客 — Attack of the week: Lucky 13
- aes —— Lucky 13 攻击的对象不是 AES 本身,而是它外面那层 CBC 模式
- [[tls-1.3]] —— TLS 1.3 的设计动机一半就是把 Lucky 13 这类攻击堵死
关联
- aes —— AES 在 CBC 模式里被使用,Lucky 13 不破 AES,破”AES + HMAC + 顺序”的组合
- [[tls-1.3]] —— TLS 1.3 删掉所有 CBC 模式,结构上免疫 Lucky 13
- heartbleed-2014 —— 同期 TLS 攻击,但走的是内存读越界路线,不同类
- libsignal —— 现代端到端加密直接用 AEAD,吸取了 Lucky 13 的教训
反向链接
- amplification-hell-2014 —— Amplification Hell 2014 — 把家用宽带放大成几百 Gbps 的反射攻击
- libsignal —— libsignal — 端到端加密的 Rust 内核
- logjam-2015 —— Logjam 2015 — 全世界共用一把锁,国家级窃听者一次撬完