首页/安全/加密与证书速查/TLS 1.3 密钥调度与密钥更新
TLS 与 HTTPS60 条

TLS 1.3 密钥调度与密钥更新

TLS 1.3 用 HKDF 分阶段派生密钥:Early Secret、Handshake Secret、Master Secret,并分别导出客户端/服务端方向的流量密钥;KeyUpdate 用于在线更新。

加密与证书速查安全更新于 2026-10-13

TLS 1.3 密钥调度

TLS 1.3 用 HKDF 把握手密钥分阶段派生,形成一条密钥调度链:Early Secret(用于 0-RTT 早期数据)、Handshake Secret(保护握手消息)、Master Secret(派生应用数据密钥)。每个阶段通过 HKDF-Extract 与 HKDF-Expand-Label 派生出客户端与服务端各自方向的流量密钥,两个方向的密钥并不相同。会话中需要更换密钥时,任一方发送 KeyUpdate 消息即可在线更新,不必重新握手,也不影响连接上的业务数据。

基本信息

派生机制HKDF-Extract 与 HKDF-Expand-Label
三个阶段Early Secret → Handshake Secret → Master Secret
方向分离client_application_traffic_secret / server_application_traffic_secret
密钥更新KeyUpdate 消息触发,无需重新握手
前向安全阶段密钥用完即从内存清除,共享密钥不能长期留存

典型使用场景

  • 协议分析与抓包解密:需要 keylog 文件才能解开 TLS 1.3 流量
  • 排查「两个方向密钥不同」引起的实现误判与自研协议对接问题
  • 评估长连接的密钥更新策略是否按预期触发
  • 理解 0-RTT 早期数据为何存在重放风险:它由会话票据派生的早期密钥保护
  • 协议实现自测:对照 RFC 8446 的标签名称核对派生结果

观察密钥更新与版本

观察密钥更新与版本
openssl s_client -connect example.com:443 -tls1_3 -keylogfile tls.keys </dev/null   # 导出 NSS key log
# 把 tls.keys 配给 Wireshark 即可解密该会话(仅限受控调试环境)
# 确认协商到的版本与套件
openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>&1 | grep -E 'Protocol|Cipher'

三阶段的密钥用途

阶段来源保护的数据
Early Secret会话票据 / PSK0-RTT 早期数据,缺乏完整前向安全且可重放
Handshake SecretECDHE 共享密钥握手消息:证书、Finished 等
Master SecretHandshake Secret应用数据,派生后仍可 KeyUpdate 更新
KeyUpdate当前应用密钥更新后同一连接继续传输,旧密钥可丢弃
SSLKEYLOGFILE 产出的 keylog 是明文流量密钥:泄漏它等于该会话可被完整解密。只允许在受控调试环境临时开启,调试结束立即删除;抓包解密只对当时记录的新会话有效,历史流量无法回溯。
实现侧要点:派生用的标签常量必须逐字节一致,包括上下文里的握手哈希;任何一端把「握手消息」与「应用数据」的标签混用,都会得到不同密钥并导致 Finished 校验失败。自研协议栈时建议先用已知测试向量对齐,再接入真实流量。

易错点

  • 在生产或共享环境开启 keylog → 会话密钥外流,等于把解密能力交给拿到日志的人
  • 把 0-RTT 早期数据与正常数据同等对待 → 早期数据可被重放,写操作与支付类请求不应使用 0-RTT
  • 长连接长期不触发 KeyUpdate → 单条流量密钥保护的数据量过大,一旦泄漏影响面扩大
  • 自行实现派生时标签字符串或 transcript 上下文写错 → 双方派生结果不一致,握手失败且难定位

数据来源与参考

  • RFC 8446 §7.1(密钥调度)
  • RFC 8446 §4.6.3(KeyUpdate)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌