本页目录

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)。

设计目标四条:

  1. 减少握手轮次⁠:2-RTT → 1-RTT(首次),0-RTT(重连)
  2. 移除不安全算法⁠:静态 RSA 密钥交换、CBC、RC4、MD5/SHA-1——凡是历史上出过事的一律清除
  3. 加密更多握手消息⁠:ServerHello 之后全部加密,被动窃听者连证书都看不到
  4. 简化⁠:约 100 个 cipher suite 砍到 5 个

与 TLS 1.2 的关键区别一表看完:

TLS 1.2TLS 1.3
首次握手2-RTT1-RTT
会话恢复session ID / ticket, 1-RTTPSK, 0-RTT
密钥交换RSA 或 (EC)DHE仅 (EC)DHE → 强制前向安全
握手加密全明文ServerHello 后全加密
Cipher suite~100 个,含密钥交换+签名5 个,只含 AEAD + hash
密钥派生PRFHKDF

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_8IoT 受限设备

密钥派生: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 草案)补上这一块:

  1. 服务器把 ECH 公钥发布在 DNS 的 HTTPS 记录(type 65)里。
  2. 客户端把真实 ClientHello(含真实 SNI)加密成内层,外层用一个掩护域名(如 cloudflare-ech.com)。
  3. 只有持有 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 区别