在 TLS 1.3 的握手过程中,客户端首先发送 ClientHello 消息,其中包含支持的密码套件、扩展和密钥共享参数。有时候服务端发现客户端提供的参数需要调整,就会发送一个特殊的响应——Hello Retry Request(简称 HRR)。本文详解 HRR 的触发条件、工作原理和实际观察方法。
什么是 Hello Retry Request
Hello Retry Request 是 TLS 1.3 引入的一种握手优化机制。当服务端收到的 ClientHello 消息中的参数不符合要求时(比如缺少必要的密钥共享、密码套件不匹配等),服务端不会直接拒绝连接,而是发送一个 HelloRetryRequest 消息,要求客户端重新发送带有正确参数的 ClientHello。
这与 TLS 1.2 的行为形成对比——TLS 1.2 中如果密码套件不兼容,服务端会直接发送 Handshake Failure 警报并终止连接。
HRR 的触发条件
HRR 主要在以下几种情况被触发:
1. Key Share 不符合要求
客户端发送的 key_share 扩展中提供的密钥共享参数不被服务端接受。常见原因包括:
- 使用了服务端不支持的椭圆曲线
- 密钥共享参数格式不正确
2. 缺少必要的 Cookie
服务端要求验证客户端身份时,会在 HRR 中包含 cookie 扩展,客户端下一次 ClientHello 必须原样返回这个 Cookie。
3. 密码套件协商
虽然现代 TLS 1.3 实现通常支持所有标准密码套件,但在某些特殊配置下,服务端可能要求客户端使用特定的套件。
HRR 工作流程
完整的 HRR 流程如下:
|
|
关键点:
- HRR 消息本身就是一个特殊的
ServerHello - 它包含
Hello Retry Request扩展(类型0xFE02) - 可能包含
cookie扩展,用于防止放大攻击 - 可能指定特定的密钥共享组
观察 HRR
虽然 HRR 在生产环境中不常见(因为现代客户端都使用标准的 key_share),但我们可以用特定方式观察 TLS 1.3 握手过程。
使用 OpenSSL 查看握手
|
|
输出示例:
|
|
查看支持的 TLS 1.3 密码套件
|
|
输出:
|
|
测试特定密钥共享组
|
|
正常情况下会显示握手成功,使用 TLS_AES_256_GCM_SHA384 等密码套件。
抓包观察完整握手
如果你想观察完整的 TLS 1.3 握手流程(包括 HRR 如果发生),可以使用 Wireshark 或 tcpdump:
|
|
然后用 Wireshark 打开,Filter 设置为 tls.handshake.type 观察各类握手消息:
- Type 1: ClientHello
- Type 2: ServerHello
- Type 6: HelloRetryRequest(如果有)
HRR 与安全性
HRR 机制增强了 TLS 1.3 的鲁棒性:
- 防止放大攻击:通过 Cookie 验证客户端 IP 真实性
- 优化握手效率:避免了因参数小问题导致整个连接失败
- 前向兼容性:服务端可以引导客户端使用更安全的参数
总结
Hello Retry Request 是 TLS 1.3 握手过程中的一个重要机制,它允许服务端在握手参数不完全匹配时,优雅地请求客户端调整参数而不是直接拒绝连接。虽然在日常使用中不常见,但它体现了 TLS 1.3 设计的灵活性和安全性。
理解 HRR 有助于:
- 排查 TLS 握手问题
- 深入理解 TLS 1.3 协议
- 优化 TLS 配置
参考来源: