SSL/TLS 握手是 HTTPS 性能的关键瓶颈。本文聚焦会话恢复(Session Resumption)技术,帮助你减少握手延迟。
问题:SSL 握手的开销#
完整的 TLS 握手需要多次网络往返:
1
2
3
4
5
|
# 测试握手时间
curl -w "Time: %{time_total}s\n" -o /dev/null -s https://example.com
# 使用 openssl 测试连接时间
time openssl s_client -connect example.com:443 </dev/null
|
对于 TLS 1.2,完整握手需要 2 个 RTT。通过会话恢复可以降至 0-1 个 RTT。
Session ID 复用#
工作原理#
服务器为每个会话分配唯一 ID,客户端在后续连接时发送该 ID,服务器据此恢复会话状态。
Nginx 配置#
1
2
3
4
5
6
7
8
9
10
11
12
|
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Session ID 复用
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
}
|
配置说明:
| 参数 |
含义 |
shared:SSL:10m |
共享缓存,约存储 40000 个会话 |
ssl_session_timeout |
会话有效期 |
ssl_session_tickets off |
禁用 Session Ticket(使用 Session ID) |
测试 Session ID 复用#
1
2
3
4
5
|
# 第一次连接,建立新会话
openssl s_client -connect example.com:443 -sess_out session.pem
# 使用保存的会话复用连接
openssl s_client -connect example.com:443 -sess_in session.pem
|
查看输出中的 Reused, TLSv1.3 表示会话已复用。
Session Ticket 复用#
工作原理#
服务器将会话状态加密后发送给客户端,客户端保存 Ticket,下次连接时发送给服务器恢复会话。
Nginx 配置#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Session Ticket 复用
ssl_session_cache off;
ssl_session_tickets on;
ssl_session_timeout 1d;
# 配置 Ticket 密钥(多服务器部署必须)
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
}
|
生成 Ticket 密钥#
1
2
3
|
# 生成 80 字节的 Ticket 密钥
openssl rand 80 > /etc/nginx/ssl/ticket.key
chmod 600 /etc/nginx/ssl/ticket.key
|
Session Ticket 的优缺点#
优点:
缺点:
- 需要安全分发 Ticket 密钥
- Ticket 密钥泄露会导致会话被解密
- 不支持前向保密(需定期轮换密钥)
TLS 1.3 的 0-RTT#
工作原理#
TLS 1.3 支持 0-RTT(Zero Round Trip Time),客户端可以在第一个请求中携带应用数据。
Nginx 配置#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 启用 TLS 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 启用 0-RTT(注意安全风险)
ssl_early_data on;
# Session Ticket 配置
ssl_session_tickets on;
ssl_session_timeout 1d;
}
|
安全注意事项#
0-RTT 存在重放攻击风险,仅适用于幂等请求:
1
2
3
4
5
6
7
|
# 限制 0-RTT 用于敏感操作
location /api/payment {
if ($ssl_early_data) {
return 425; # Too Early
}
# ... 正常处理
}
|
OCSP Stapling#
减少证书验证延迟:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_stapling_responder http://ocsp.example.com;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
}
|
测试 OCSP Stapling:
1
2
3
4
5
6
|
# 检查服务器是否启用 OCSP Stapling
openssl s_client -connect example.com:443 -status < /dev/null 2>&1 | \
grep -A 17 "OCSP response"
# 或者使用在线工具
# https://www.ssllabs.com/ssltest/
|
性能测试对比#
使用 openssl s_time 测试握手性能:
1
2
3
4
5
|
# 测试 100 个连接的性能
openssl s_time -connect example.com:443 -new -time 10
# 测试会话复用性能
openssl s_time -connect example.com:443 -time 10
|
预期结果#
| 场景 |
连接数/秒 |
| 完整握手 |
10-50 |
| Session ID 复用 |
100-500 |
| Session Ticket 复用 |
100-500 |
| TLS 1.3 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
25
26
27
|
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 协议配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# 会话恢复
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
ssl_early_data on;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# HSTS
add_header Strict-Transport-Security "max-age=31536000" always;
}
|
验证配置:
1
2
3
4
5
6
7
8
9
|
# 测试配置语法
nginx -t
# 重载配置
nginx -s reload
# 测试最终效果
openssl s_client -connect example.com:443 -tls1_3 < /dev/null 2>&1 | \
grep -E "Protocol|Reused|Verify"
|
参考来源#