TLS 1.3 握手是什么
TLS 1.3 把密钥协商压缩到一次往返:客户端在 ClientHello 里直接带上 key_share,服务端回 ServerHello 后双方就能算出握手密钥,随后在加密信道里发送 EncryptedExtensions、Certificate、CertificateVerify 与 Finished。相比 1.2 的 2-RTT,首字节延迟明显下降,而且证书不再明文暴露。
基本信息
| 标准 | RFC 8446 §4 |
|---|---|
| 消息序列 | ClientHello(key_share) → ServerHello(key_share) → 加密的扩展、证书、CertificateVerify、Finished → Finished |
| 轮次 | 1-RTT(选到不被接受的曲线组时会触发 HelloRetryRequest 变成 2-RTT) |
| 0-RTT | 基于 PSK 的 early data,存在重放风险 |
| 密钥派生 | HKDF 分层派生早期密钥、握手密钥与主密钥 |
| 记录层版本 | 仍写 0x0303,实际版本靠 supported_versions 扩展协商 |
典型使用场景
- 新建站点与网关:默认开启 1.3 以降低握手延迟
- 弱网与移动端:少一次往返,对高时延链路收益明显
- 证书隐私要求:证书在加密信道内传输,中间设备无法直接读取
- 内部服务间通信:配合 mTLS 做双向认证
- 会话恢复优化:用会话票据与 PSK 实现快速重连,同时注意票据密钥轮换
观察握手与密钥交换组
观察握手与密钥交换组
# 查看协商结果与临时密钥类型
openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null 2>&1 | grep -E 'Protocol|Cipher|Peer Temp Key|Server Temp Key'
# 打印握手消息:ClientHello 之后基本已进入加密记录
openssl s_client -connect example.com:443 -tls1_3 -msg </dev/null 2>&1 | head -40
# 指定单一 1.3 套件测试
openssl s_client -connect example.com:443 -tls1_3 -ciphersuites TLS_AES_128_GCM_SHA256 </dev/null 2>&1 | grep 'Cipher'
# 抓包观察(能看到 ClientHello 与加密记录的分界)
tcpdump -i eth0 -w tls13.pcap 'tcp port 443' -c 200握手阶段与密钥
| 阶段 | 主要消息 | 使用的密钥 |
|---|---|---|
| 第一往返 | ClientHello、ServerHello | 明文传输,含 key_share 与 supported_versions |
| 握手密钥 | EncryptedExtensions、Certificate、CertificateVerify、Finished | Handshake Traffic Secret |
| 应用密钥 | 双方 Finished 之后 | Application Traffic Secret |
| 会话恢复 | PreSharedKey 扩展与票据 | PSK 派生,可配合 0-RTT |
| 密钥更新 | KeyUpdate | 更新应用流量密钥,与重协商无关 |
选到客户端未提供 key_share 的曲线组时会触发 HelloRetryRequest,握手退回两次往返,表现为建连时间明显变长。把 X25519 与 P-256 放在服务端优先位置,并保证客户端支持,是减少这类情况最直接的做法。
0-RTT 的 early data 可以被攻击者复制重放:它不提供完整的前向保密与防重放保证。只对幂等请求开放,并对写操作、支付类接口关闭,同时在服务端做重放检测。
证书体积会影响握手表现:RSA 4096 位证书配合较长链会使握手消息跨越多个 TCP 段,弱网下更容易触发分段与重传。控制证书链长度、优先 ECDSA 证书,能减少这类问题。