HTTPS 握手耗时过长的常见原因之一是证书链不完整,导致客户端需要额外发起 HTTP 请求下载中间证书。最直接的处理方式是确保 Web 服务器在 TLS 握手时一次性发送完整的证书链(叶子证书 + 中间证书),避免客户端因缺少中间证书而发起额外的 AIA 请求,从而减少往返次数(RTT)。
先说结论:优化证书链的核心在于“服务端发全”和“链长最短”,这能避免客户端额外发起 AIA 请求,但具体耗时收益取决于客户端网络环境。
- 先定位:使用 curl 测量握手耗时,并结合 OpenSSL 检查证书链完整性,确认瓶颈是否由缺失中间证书引起。
- 先做:将叶子证书与中间证书合并为一个文件,并在 Nginx 或 Apache 配置中指向该完整链文件,同时补全 OCSP Stapling 配置。
- 再验证:对比优化前后的 SSL 握手耗时,并通过 SSL Labs 确认链 issues 消失。
如何确认瓶颈在证书链
在优化之前,需确认握手慢是由证书链缺失引起,而非单纯的网络延迟。如果证书链不完整,客户端会在握手后额外发起 HTTP 请求下载中间证书,这会显著增加耗时。
1. 检查证书链完整性
使用 OpenSSL 查看服务器发送的证书数量。正常情况下应看到至少两个证书(叶子证书和中间证书):
openssl s_client -connect yourdomain.com:443 -showcerts | grep "s:"
如果输出中只有一个证书(Certificate 0),说明中间证书未发送,客户端极可能需要额外往返获取。
2. 排除网络延迟干扰
如果证书链完整但握手依然慢,可能是网络 RTT 过高。此时优化证书链收益有限,应重点排查网络链路或 CDN 配置。
测量握手耗时
使用 curl 命令可以量化 SSL 握手阶段的具体耗时,以便优化前后对比。SSL 握手耗时近似等于 time_appconnect 减去 time_connect。
1. 创建测量格式文件
创建一个名为 curl-format.txt 的文件,内容如下:
time_namelookup: %{time_namelookup}s\ntime_connect: %{time_connect}s\ntime_appconnect: %{time_appconnect}s\nSSL Handshake: %{time_appconnect} - %{time_connect}s\n2. 执行测量命令
curl -w "@curl-format.txt" -o /dev/null -s https://yourdomain.com
记录 SSL Handshake 的数值。优化配置后再次运行,对比该数值是否下降。
修复证书链与 OCSP 配置
1. 合并证书文件
如果你使用的是 Let's Encrypt 等 CA,通常会有单独的叶子证书和中间证书文件。需要将它们按顺序合并。以 Nginx 为例,创建一个 fullchain.pem:
cat cert.pem intermediate.pem > fullchain.pem
注意顺序:必须是叶子证书在前,中间证书在后。根证书通常不需要发送,因为客户端本地已有。
2. 配置 Web 服务器
Nginx 配置示例:
ssl_certificate /path/to/fullchain.pem;\nssl_certificate_key /path/to/privkey.pem;
Apache 配置示例:
SSLCertificateFile /path/to/fullchain.pem\nSSLCertificateKeyFile /path/to/privkey.pem
3. 开启 OCSP Stapling(必须补全配置)
OCSP Stapling 能避免客户端单独查询证书吊销状态,进一步减少握手往返。Nginx 中开启时,必须配置 ssl_trusted_certificate,否则 Stapling 可能静默失败或 Nginx 启动报错:
ssl_stapling on;\nssl_stapling_verify on;\nssl_trusted_certificate /path/to/fullchain.pem;
此外,确保服务器能正常解析 OCSP 响应者的域名(检查 resolv.conf 或 DNS 配置),否则 Stapling 无法获取状态。
验证优化效果
1. 耗时对比
再次运行 curl 测量命令,观察 SSL Handshake 时间是否减少。在网络波动环境下,建议多次测量取平均值。
2. 命令行复核
运行 openssl s_client -connect yourdomain.com:443 -showcerts,确认输出中包含了中间证书,且 Verify return code: 0 (ok)。
3. 在线工具检测
使用 SSL Labs (ssllabs.com) 进行测评,查看 "Chain issues" 是否为 None,以及 "Extra Download" 相关提示是否消失。
常见坑
1. 证书顺序颠倒
合并证书时如果把中间证书放在叶子证书前面,部分客户端(尤其是旧版 Android 或 Java 环境)可能无法正确构建信任链,导致握手失败。
2. 交叉签名遗留问题
Let's Encrypt 曾在 2021 年切换根证书(从 DST Root CA X3 到 ISRG Root X1)。如果服务器配置了旧的交叉签名链,部分旧设备可能尝试下载已过期的中间证书,导致验证错误。建议直接使用最新的短链。
3. 混淆 fullchain 和 cert
某些面板或脚本生成的 cert.pem 仅包含叶子证书,而 fullchain.pem 才包含中间证书。配置时务必确认文件内容,不要只看文件名。
4. OCSP 配置不完整
仅开启 ssl_stapling 而忽略 ssl_trusted_certificate 或 DNS 配置,会导致 Nginx 日志中出现 OCSP 相关错误,且客户端无法受益。