本页目录
TLS 1.3 握手
TLS 1.3 把握手压缩到 1-RTT,0-RTT 甚至零往返——手段是砍掉静态 RSA、强制前向安全、把密钥协商提前到 ClientHello。干净利落的协议设计,代价是 0-RTT 丧失了重放保护。
概述
TLS 1.3(RFC 8446, 2018)是对 TLS 1.2 的最大改版,而它的核心手法可以用一句话概括:客户端不再"问服务器想用什么",而是直接猜——在 ClientHello 里就带上 ECDHE 公钥(key_share),赌服务器支持 x25519(几乎总是赌对)。于是 TLS 1.2 里"先协商算法、再交换密钥"的两轮往返,坍缩成一轮;有会话票据时甚至零往返(0-RTT)。
设计目标四条:
- 减少握手轮次:2-RTT → 1-RTT(首次),0-RTT(重连)
- 移除不安全算法:静态 RSA 密钥交换、CBC、RC4、MD5/SHA-1——凡是历史上出过事的一律清除
- 加密更多握手消息:ServerHello 之后全部加密,被动窃听者连证书都看不到
- 简化:约 100 个 cipher suite 砍到 5 个
与 TLS 1.2 的关键区别一表看完:
| TLS 1.2 | TLS 1.3 | |
|---|---|---|
| 首次握手 | 2-RTT | 1-RTT |
| 会话恢复 | session ID / ticket, 1-RTT | PSK, 0-RTT |
| 密钥交换 | RSA 或 (EC)DHE | 仅 (EC)DHE → 强制前向安全 |
| 握手加密 | 全明文 | ServerHello 后全加密 |
| Cipher suite | ~100 个,含密钥交换+签名 | 5 个,只含 AEAD + hash |
| 密钥派生 | PRF | HKDF |
1-RTT 完整握手流程
sequenceDiagram
participant C as Client
participant S as Server
C->>S: ClientHello<br>key_share(x25519 公钥), cipher_suites,<br>supported_groups, signature_algorithms
Note over S: 已能算出共享密钥<br>→ 之后的消息全部加密
S->>C: ServerHello (key_share)<br>🔒 EncryptedExtensions<br>🔒 Certificate + CertificateVerify<br>🔒 Finished
Note over C: 验证证书与签名,<br>算出相同密钥
C->>S: 🔒 Finished + 应用数据
Note over C,S: 第一个 RTT 结束时数据已在路上<br>(TLS 1.2 要等两个 RTT)
流程里藏着三个设计要点:
key_share:密钥协商提前。客户端为若干椭圆曲线各附一把 ECDHE 公钥(x25519 32 字节、secp256r1 65 字节),服务器挑一条曲线、回自己的公钥——双方在第一次往返内就完成了 Diffie-Hellman。猜错了怎么办?服务器回 HelloRetryRequest 指定曲线,客户端重发 ClientHello,退化为 2-RTT——实践中几乎不发生。
认证与保密解耦。TLS 1.2 的静态 RSA 把两件事绑在一起:服务器私钥既证明身份、又参与解密密钥——私钥一旦泄露,过去录下的全部流量都能回放解密。TLS 1.3 里密钥只来自每次全新的 ECDHE(前向安全),证书私钥只做一件事:对握手记录签名(CertificateVerify)证明"我确实是这个域名的主人"。
Cipher suite 只剩 AEAD + hash 的组合:
| Suite | 用途 |
|---|---|
| TLS_AES_128_GCM_SHA256 | 默认主力 |
| TLS_AES_256_GCM_SHA384 | 更高安全边际 |
| TLS_CHACHA20_POLY1305_SHA256 | 无 AES 硬件加速的移动端 |
| TLS_AES_128_CCM_SHA256 / CCM_8 | IoT 受限设备 |
密钥派生:HKDF
TLS 1.3 用 HKDF 取代 1.2 的 PRF,派生链是一个三级"密钥梯":
Early Secret = HKDF-Extract(salt=0, PSK 或 0) ← 0-RTT 密钥从这层出
Handshake Secret = HKDF-Extract(Early Secret, ECDHE 共享密钥) ← 握手加密密钥
Master Secret = HKDF-Extract(Handshake Secret, 0) ← 应用数据密钥
每一步 Expand 都混入 transcript hash(至今全部握手消息的哈希)——所以即使两次握手用了同一个 PSK,只要任何一条消息有一个字节不同,派生出的密钥就完全不同。这也是握手防篡改的根:改了任何消息,双方算出的 Finished 校验值对不上。
0-RTT PSK:重连零往返
首次握手后服务器发一张 session ticket(本质是 PSK)。重连时客户端在 ClientHello 里带上 PSK 标识和 binder,同一个包里直接附上加密的应用数据(early data)——服务器验证 PSK 后立即处理,一个往返都不等。
代价是安全性打折,必须清楚三条:
- 重放攻击:攻击者原样重发抓到的 0-RTT 包,服务器会再处理一遍 early data。协议层没有完整防御,只能应用层自保——0-RTT 里只放幂等操作(HTTP 的 GET/HEAD),这正是各大 CDN 的实现方式。
- 无前向安全:early data 的密钥只从 PSK 派生,PSK 泄露则过去所有 0-RTT 数据可解密(1-RTT 部分不受影响,因为混入了新的 ECDHE)。
- 服务器可用
max_early_data_size限制敞口,或干脆拒绝 early data 强制回落 1-RTT。
Encrypted ClientHello (ECH)
TLS 1.3 遗留的最后一块明文:ClientHello 本身——里面的 SNI(目标域名)让中间设备仍能按域名审查/封锁。ECH(ESNI 的继任,RFC 草案)补上这一块:
- 服务器把 ECH 公钥发布在 DNS 的 HTTPS 记录(type 65)里。
- 客户端把真实 ClientHello(含真实 SNI)加密成内层,外层用一个掩护域名(如 cloudflare-ech.com)。
- 只有持有 ECH 私钥的服务器能解开内层;路径上的观察者只看到掩护域名。
配合 DoH/DoT(DNS 查询本身也加密,见 DNS 隐私),"用户访问了哪个网站"这条元数据才算真正藏住。
相关
TLS 1.2 的完整握手与它的历史包袱见 TLS 1.2 握手;证书链如何被验证见证书与 PKI;QUIC 把 TLS 1.3 直接内建进传输层,见 HTTP/3。
参考
- RFC: 8446 (Appendix D 有 0-RTT 的安全分析)
- ECH: draft-ietf-tls-esni
- 工具:
openssl s_client -tls1_3 -connect host:443· Wireshark 过滤tls.handshake.type - 可视化: tls13.xargs.org (逐字节图解 TLS 1.3 握手,极好)
Keywords: TLS 1.3, TLS1.3 握手流程, 1-RTT, key_share, ECDHE, 前向安全, forward secrecy, 0-RTT, PSK, 重放攻击, session ticket, HKDF, transcript hash, ECH, SNI, cipher suite, TLS1.2 区别