在 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 扩展中提供的密钥共享参数不被服务端接受。常见原因包括:

  • 使用了服务端不支持的椭圆曲线
  • 密钥共享参数格式不正确

服务端要求验证客户端身份时,会在 HRR 中包含 cookie 扩展,客户端下一次 ClientHello 必须原样返回这个 Cookie。

3. 密码套件协商

虽然现代 TLS 1.3 实现通常支持所有标准密码套件,但在某些特殊配置下,服务端可能要求客户端使用特定的套件。

HRR 工作流程

完整的 HRR 流程如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
客户端                    服务端
  |                         |
  |--- ClientHello (尝试1)--->|
  |    (key_share 不符合)    |
  |                         |
  |<-- HelloRetryRequest ---|
  |    (包含 Cookie)        |
  |                         |
  |--- ClientHello (尝试2)--->|
  |    (包含正确的 key_share)|
  |    (包含 Cookie)         |
  |                         |
  |<------ ServerHello ------|
  |                         |
  |... 继续握手 ...          |

关键点:

  • HRR 消息本身就是一个特殊的 ServerHello
  • 它包含 Hello Retry Request 扩展(类型 0xFE02
  • 可能包含 cookie 扩展,用于防止放大攻击
  • 可能指定特定的密钥共享组

观察 HRR

虽然 HRR 在生产环境中不常见(因为现代客户端都使用标准的 key_share),但我们可以用特定方式观察 TLS 1.3 握手过程。

使用 OpenSSL 查看握手

1
2
# 观察 TLS 1.3 握手详细信息
openssl s_client -connect cloudflare.com:443 -tls1_3 -msg </dev/null 2>&1 | head -30

输出示例:

1
2
3
4
>>> TLS 1.3, Handshake [length 014a], ClientHello
    01 00 00 c6 03 03 ...
<<< TLS 1.3, Handshake [length 007a], ServerHello
    02 00 00 76 03 03 ...

查看支持的 TLS 1.3 密码套件

1
2
# 列出 OpenSSL 支持的 TLS 1.3 密码套件
openssl ciphers -s -tls1_3

输出:

1
2
3
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256

测试特定密钥共享组

1
2
# 使用特定密钥组尝试连接
openssl s_client -connect cloudflare.com:443 -tls1_3 -groups secp256r1 </dev/null 2>&1 | grep -E "Cipher|TLSv1.3"

正常情况下会显示握手成功,使用 TLS_AES_256_GCM_SHA384 等密码套件。

抓包观察完整握手

如果你想观察完整的 TLS 1.3 握手流程(包括 HRR 如果发生),可以使用 Wireshark 或 tcpdump:

1
2
# 捕获 TLS 握手数据包
sudo tcpdump -i any -w tls-handshake.pcap host cloudflare.com and port 443

然后用 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 配置

参考来源: