TLS 1.3 在握手效率和安全机制上做了重大改进。除了优化的握手流程外,协议还定义了一系列 Post-Handshake 消息,在握手完成后处理会话恢复、密钥更新等重要功能。理解这些消息对于深入掌握 TLS 1.3 至关重要。

什么是 Post-Handshake 消息?

在 TLS 1.3 中,握手完成后双方进入加密通信阶段。此时协议定义了一组特殊消息,用于处理握手后的事务:

  • NewSessionTicket:发送会话票据,用于后续会话恢复
  • KeyUpdate:更新加密密钥,保持前向安全性
  • CertificateRequest:请求客户端证书(握手后认证)
  • Certificate:提供客户端证书
  • CertificateVerify:验证客户端证书

这些消息与主握手流程独立,通过独立的加密通道传输。

NewSessionTicket(会话票据)

原理

NewSessionTicket 是 TLS 1.3 会话恢复机制的核心。当客户端和服务器完成完整握手后,服务器可以发送一个加密的会话票据给客户端。下次连接时,客户端可以使用这个票据恢复会话,无需完整握手,从而实现 1-RTT 甚至 0-RTT 的快速连接。

工作流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
完整握手:
客户端                                          服务器
   |                                              |
   |--------------- ClientHello ----------------->|
   |           (附 session_id / session_ticket)   |
   |<-------------- ServerHello ------------------|
   |<-------------- Certificate ------------------|
   |<-------------- CertificateVerify ------------|
   |<---------------- Finished -------------------|
   |--------------- Finished -------------------->|
   |                                              |
   |================ 加密通道 ====================|
   |                                              |
   |<------------- NewSessionTicket -------------|
   |                                              |
   
快速恢复(0-RTT):
客户端                                          服务器
   |                                              |
   |-------- ClientHello + EarlyData + Ticket -->|
   |<-------- ServerHello + EarlyData ------------|
   |<---------------- Finished -------------------|
   |--------------- Finished -------------------->|
   |                                              |

实际验证

使用 OpenSSL 查看 TLS 1.3 会话恢复:

1
2
3
# 查看 TLS 1.3 连接(会话票据默认启用)
$ echo | openssl s_client -connect cloudflare.com:443 -tls1_3 2>&1 | grep -E "Protocol|Cipher"
New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256

查看会话恢复过程(-reconnect 使用相同会话ID重新连接):

1
2
3
4
5
# 第一次连接后,使用 -reconnect 测试会话恢复
$ openssl s_client -connect cloudflare.com:443 -tls1_3 -reconnect 2>&1 | grep -E "Protocol|Cipher"
New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256

可以看到多次连接的 Cipher 相同,说明会话票据恢复成功。

票据生命周期

会话票据包含时间戳信息,过期后无法使用:

1
2
# 解密会话票据(需要服务器密钥)
# 注意:客户端无法直接解密票据,这是服务器的责任

安全考虑

  1. 前向安全性:会话票据使用会话密钥加密,该密钥从主密钥派生
  2. 票据有效期:服务器应设置合理的票据 lifetime,通常为数小时到数天
  3. 0-RTT 风险:使用 0-RTT 数据可能面临重放攻击风险

KeyUpdate(密钥更新)

TLS 1.3 允许在握手完成后动态更新加密密钥,无需重新握手。这通过 KeyUpdate 消息实现,详细机制在 TLS 1.3 密钥更新机制解析 中已有讲解。

核心要点:

  • 使用 HKDF 从当前密钥派生出新密钥
  • 可以单向或双向更新
  • 开销极低,仅需传输几字节

Post-Handshake Authentication(握手后认证)

TLS 1.3 引入了灵活的握手后认证机制,允许服务器在握手完成后请求客户端证书。

原理

传统的 TLS 握手要求客户端证书在主握手阶段提供。TLS 1.3 支持 延迟认证:先完成握手建立加密通道,然后在需要时请求客户端证书。

工作流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
正常握手完成后(已加密通道):
客户端                                          服务器
   |                                              |
   |<---------- CertificateRequest --------------|
   |         (请求客户端证书)                      |
   |                                              |
   |----------- Certificate ---------------------|
   |----------- CertificateVerify --------------->
   |                                              |
   |------------ Finished ---------------------->|
   |                                              |

实际验证

配置 Nginx 要求客户端证书:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /path/to/server.crt;
    ssl_certificate_key /path/to/server.key;

    # 启用 TLS 1.3
    ssl_protocols TLSv1.3;

    # 要求客户端证书(握手后认证)
    ssl_verify_client on;

    # 客户端证书颁发机构
    ssl_client_certificate /path/to/ca.crt;
}

使用 OpenSSL 测试:

1
2
3
4
5
6
7
8
# 使用客户端证书连接
$ openssl s_client -connect example.com:443 -tls1_3 \
    -cert /path/to/client.crt -key /path/to/client.key

# 查看连接信息
$ openssl s_client -connect example.com:443 -tls1_3 \
    -cert /path/to/client.crt -key /path/to/client.key 2>&1 | \
    grep -E "Client Certificate|Verify Return"

与 TLS 1.2 的区别

特性 TLS 1.2 TLS 1.3
客户端证书时机 握手期间 握手后(可选)
认证灵活性 固定 可选、按需
0-RTT 支持 支持

消息类型识别

TLS 1.3 Post-Handshake 消息通过 Content Type 区分:

Content Type 消息类型
20 KeyUpdate
21 NewSessionTicket
22 CertificateRequest
23 Certificate
24 CertificateVerify
25 Finished

可以通过 Wireshark 观察这些消息:

1
2
3
# Wireshark 过滤器
tls.record.content_type == 20  # KeyUpdate
tls.record.content_type == 21  # NewSessionTicket

实际应用建议

1. 会话恢复配置

1
2
3
# Nginx 配置会话票据
ssl_sessionTickets on;
ssl_session_timeout 1d;

2. 密钥更新策略

大多数服务器自动处理密钥更新,无需手动配置。如需自定义:

1
2
3
# Nginx TLS 1.3 配置
ssl_protocols TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;

3. 客户端认证策略

根据业务需求选择认证时机:

  • 高安全要求:握手期间认证(传统方式)
  • 灵活认证:握手后认证(TLS 1.3)

总结

TLS 1.3 的 Post-Handshake 消息机制提供了强大的功能:

  • NewSessionTicket:实现高效的会话恢复,减少延迟
  • KeyUpdate:保持前向安全性,无需完整握手
  • Post-handshake Auth:灵活的客户端认证机制

这些机制共同使 TLS 1.3 成为一个高效、安全、易用的协议。在实际部署中,正确配置这些特性可以显著提升用户体验和安全性。


参考来源