目录

HTTPS 握手优化实战:从 200ms 到 50ms 的全链路调优

用户抱怨"网站打开慢"。用 Chrome DevTools 分析发现,TTFB (Time To First Byte) 高达 400ms,其中 HTTPS 握手占了 200ms。这篇文章记录了将握手时间优化到 50ms 的全过程。

一、问题诊断

1.1 抓包分析

1
2
3
4
5
6
7
8
9
# 使用 curl 测量各阶段耗时
curl -w "@curl-format.txt" -o /dev/null -s https://terra-nas.com

# curl-format.txt:
#   time_namelookup:  %{time_namelookup}s\n
#   time_connect:     %{time_connect}s\n
#   time_appconnect:  %{time_appconnect}s\n
#   time_starttransfer: %{time_starttransfer}s\n
#   time_total:       %{time_total}s\n

结果

1
2
3
4
5
time_namelookup:  0.020s   # DNS
time_connect:     0.060s   # TCP (RTT ≈ 40ms)
time_appconnect:  0.260s   # TLS 握手完成!
time_starttransfer: 0.280s
time_total:       0.350s

TLS 握手耗时 200ms,这是 TCP 连接后到应用数据传输的时间差。

1.2 握手耗时分解

使用 openssl s_client 详细分析:

1
openssl s_client -connect terra-nas.com:443 -status 2>&1 | head -50

发现问题:

  1. 服务器使用 TLS 1.2(需要 2-RTT 握手)
  2. OCSP 响应客户端自己去查询(额外延迟)
  3. 证书链包含 3 个证书(传输量大)

二、TLS 握手原理

2.1 TLS 1.2 握手(2-RTT)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Client                              Server
  |                                    |
  |------- ClientHello --------------->|  RTT 1
  |<------ ServerHello + Cert ---------|  
  |<------ ServerKeyExchange ----------|
  |<------ ServerHelloDone ------------|
  |                                    |
  |------- ClientKeyExchange --------->|  RTT 2
  |------- ChangeCipherSpec ---------->|
  |------- Finished ------------------>|
  |<------ ChangeCipherSpec -----------|
  |<------ Finished -------------------|
  |                                    |
  |======= Application Data ==========>|  终于可以发数据了!

耗时:至少 2 个 RTT,假设 RTT=40ms,则 TLS 握手 ≥ 80ms。

但我们测到 200ms,说明还有其他开销。

2.2 TLS 1.3 握手(1-RTT)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Client                              Server
  |                                    |
  |------- ClientHello + KeyShare ---->|  RTT 1
  |<------ ServerHello + KeyShare -----|
  |<------ EncryptedExtensions --------|
  |<------ Certificate ----------------|
  |<------ CertificateVerify ----------|
  |<------ Finished -------------------|
  |------- Finished ------------------>|
  |                                    |
  |======= Application Data ==========>|  1-RTT 后即可发数据!

优化点:ClientHello 直接携带密钥交换参数,减少一个 RTT。

2.3 0-RTT (TLS 1.3 Early Data)

1
2
3
4
5
6
7
8
# 首次连接后,服务器发送 Session Ticket
# 后续连接可以直接发送加密数据

Client                              Server
  |                                    |
  |------- ClientHello + EarlyData --->|  0-RTT!
  |======= 应用数据已开始传输 ===========>|
  |<------ ServerHello + ... ----------|

注意:0-RTT 有重放攻击风险,只适合幂等请求。

三、优化措施

3.1 启用 TLS 1.3

Nginx 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
server {
    listen 443 ssl http2;
    
    ssl_protocols TLSv1.2 TLSv1.3;  # 同时支持 1.2 和 1.3
    ssl_prefer_server_ciphers off;   # TLS 1.3 不需要这个
    
    # TLS 1.3 密码套件
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    
    # 启用 0-RTT(注意安全风险)
    ssl_early_data on;
}

效果:TLS 握手从 2-RTT 降到 1-RTT,节省 40ms。

3.2 OCSP Stapling

问题:客户端需要验证证书是否被吊销,传统方式是向 CA 发送 OCSP 请求。

1
2
3
4
5
传统方式:
Client --> Server: 获取证书
Client --> CA (OCSP): 证书有效吗?  ← 额外 RTT!
CA --> Client: 有效
Client --> Server: 继续握手

OCSP Stapling:服务器预先获取 OCSP 响应,握手时一起发给客户端。

1
2
3
4
5
6
7
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;

# 设置 OCSP 响应器
resolver 8.8.8.8 valid=300s;
resolver_timeout 5s;

验证

1
2
openssl s_client -connect terra-nas.com:443 -status 2>&1 | grep -A 15 "OCSP"
# OCSP Response Status: successful

效果:省去客户端 OCSP 查询,节省 50-100ms。

3.3 证书链优化

问题:完整证书链可能有 3-4 个证书,增加传输量。

1
2
3
4
5
# 查看证书链
openssl s_client -connect terra-nas.com:443 -showcerts 2>/dev/null | grep "s:"
# s:/CN=terra-nas.com
# s:/CN=Let's Encrypt Authority X3  # 中间证书
# s:/CN=DST Root CA X3              # 根证书(不应该发送!)

优化:只发送网站证书 + 中间证书,不发根证书(浏览器已内置)。

1
2
3
4
5
6
7
# 正确的证书文件应该是:
# 1. 网站证书
# 2. 中间证书
# (不包含根证书)

ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;

效果:减少 1KB 左右传输量。

3.4 Session Resumption

Session Ticket(无状态恢复)

1
2
3
4
5
ssl_session_tickets on;
ssl_session_timeout 1d;  # 24 小时有效

# 自定义 ticket key(多服务器需要共享)
ssl_session_ticket_key /path/to/ticket.key;

Session Cache(有状态恢复)

1
2
ssl_session_cache shared:SSL:10m;  # 10MB 共享缓存
ssl_session_timeout 1d;

效果:回访用户 TLS 握手降为 1-RTT 甚至 0-RTT。

3.5 使用 ECDSA 证书

RSA 证书签名验证较慢,ECDSA 更快且密钥更短。

1
2
3
4
5
6
7
8
# 生成 ECDSA 私钥
openssl ecparam -genkey -name prime256v1 -out privkey.pem

# 生成 CSR
openssl req -new -key privkey.pem -out csr.pem

# 申请证书(Let's Encrypt 支持 ECDSA)
certbot certonly --csr csr.pem

对比

类型密钥长度安全性等价签名速度
RSA 20482048 bits112 bits
ECDSA P-256256 bits128 bits快 3-4x

3.6 启用 HTTP/2

HTTP/2 复用一个 TCP 连接,TLS 握手只需一次。

1
listen 443 ssl http2;

四、性能对比

4.1 优化前后测量

1
2
3
4
5
6
7
# 优化前
curl -w "TLS: %{time_appconnect}s\n" -o /dev/null -s https://terra-nas.com
# TLS: 0.260s

# 优化后
curl -w "TLS: %{time_appconnect}s\n" -o /dev/null -s https://terra-nas.com
# TLS: 0.050s

4.2 耗时分解

优化项节省时间
TLS 1.3 (1-RTT)40ms
OCSP Stapling60ms
Session Resumption40ms
证书链优化10ms
ECDSA 证书5ms
总计~150ms

五、监控与验证

5.1 SSL Labs 测试

访问 https://www.ssllabs.com/ssltest/ 获取详细评分。

关注指标:

  • Protocol Support: TLS 1.3 ✓
  • OCSP Stapling: Yes ✓
  • Certificate Chain: 2 certificates ✓

5.2 Chrome DevTools

1
2
3
4
5
Timing 面板:
  DNS Lookup:     20ms
  Initial connection: 50ms  ← 大幅降低
  SSL:            30ms      ← TLS 握手
  TTFB:           80ms

5.3 Prometheus 监控

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 监控 TLS 握手时间
- job_name: 'nginx'
  metrics_path: '/metrics'
  static_configs:
    - targets: ['localhost:9113']

# 告警规则
- alert: HighTLSHandshakeTime
  expr: nginx_http_ssl_handshake_time_seconds_bucket{le="0.1"} / nginx_http_ssl_handshake_time_seconds_count < 0.9
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "超过 10% 的 TLS 握手耗时 > 100ms"

六、完整配置示例

 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
28
29
30
31
server {
    listen 443 ssl http2;
    server_name terra-nas.com;
    
    # 证书
    ssl_certificate /etc/letsencrypt/live/terra-nas.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/terra-nas.com/privkey.pem;
    
    # 协议与密码套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/terra-nas.com/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    
    # Session 复用
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets on;
    
    # 0-RTT (谨慎使用)
    ssl_early_data on;
    
    # 安全头
    add_header Strict-Transport-Security "max-age=31536000" always;
    
    # ...
}

七、总结

优化技术原理效果
TLS 1.31-RTT 握手-40ms
OCSP Stapling服务器预取证书状态-60ms
Session Resumption复用之前的握手结果-40ms
证书链精简减少传输量-10ms
ECDSA 证书更快的签名算法-5ms

核心收获:HTTPS 性能优化不只是选择算法,更是减少往返次数 (RTT)。在高延迟网络(如跨国访问)中,这些优化效果更加明显。