Nginx HTTPS 与 TLS 加固:证书链、HTTP2 与 OCSP 配置

深入讲解 HTTPS 与 TLS 加固。涵盖证书链、协议套件、HTTP2 与 ALPN、OCSP Stapling、会话复用与 HSTS 最佳实践。

HTTPS 不只是在监听端口后加上 ssl,而是一整套证书链、协议版本、加密套件与会话复用的工程组合。配置不当的 HTTPS 可能面临证书链不完整导致安卓客户端握手失败、只支持旧协议被安全扫描降级、未开启 OCSP Stapling 让每次握手都要外连 CA 等服务问题。本文从证书链结构讲起,覆盖 TLS 协议与套件策略、HTTP/2 与 ALPN、OCSP Stapling、会话复用与 HSTS,给出可直接落地的生产配置。

核心认知:TLS 安全是"协议版本 + 套件白名单 + 证书可信链"三者的交集。三者中任一项配置错误,都会让 HTTPS 形同虚设或直接不可用。

1. 证书链与 ssl_certificate

1.1 证书链的组成

一个完整的 HTTPS 证书链通常包含三部分:

终端实体证书(example.com)          ← 网站证书
    ↑ 由谁签发
中间 CA 证书(R10 / Let's Encrypt) ← 通常已包含在 fullchain
    ↑ 由谁签发
根 CA 证书(ISRG Root X1)          ← 客户端内置信任

1.2 Nginx 证书配置

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
文件内容说明
fullchain.pem证书 + 中间 CANginx 建议用这个
cert.pem仅终端证书缺少中间链会握手失败
privkey.pem私钥权限需 600,勿外泄
chain.pem仅中间 CA可拼进 fullchain

避坑:证书链不完整是安卓端握手失败的常见原因。fullchain.pem 必须包含中间 CA;可随时用 openssl s_client -connect 验证链是否完整。

2. 协议版本与加密套件

2.1 协议版本选择

server {
    ssl_protocols TLSv1.2 TLSv1.3;   # 关闭 TLSv1/1.1 与 SSLv3
    ssl_prefer_server_ciphers on;
}
协议状态说明
SSLv3 / TLSv1.0禁用POODLE/BEAST 漏洞
TLSv1.1禁用过于老旧
TLSv1.2启用兼容性主力
TLSv1.3启用更安全更快,握手缩短

2.2 加密套件白名单

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';

选择原则:

维度要求
密钥交换仅 ECDHE(前向保密)
分组模式AES-GCM / ChaCha20-Poly1305
对称密钥AES-128/256
禁止项RC4、3DES、CBC 系弱套件

核心认知:TLSv1.3 的套件由协议内建,上述 ssl_ciphers 主要约束 TLSv1.2 握手。坚持 ECDHE 与 GCM,可同时满足前向保密与性能。

3. HTTP2 与 ALPN

3.1 开启 HTTP2

server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate     fullchain.pem;
    ssl_certificate_key privkey.pem;
}

新版 Nginx 用独立指令:

server {
    listen 443 ssl;
    http2 on;                     # Nginx 1.25.1+ 推荐写法
}

3.2 ALPN 协商

ALPN 让客户端与服务器在 TLS 握手中协商应用协议:

# 默认即可,Nginx 会向客户端通告 h2 与 http/1.1
ssl_alpn_protocols  h2 http/1.1;
协商结果含义
h2客户端与服务器都支持 HTTP/2
http/1.1退化到 HTTP/1.1
none老客户端,仍可工作

3.3 HTTP2 的收益

能力HTTP/1.1HTTP/2
连接复用队头阻塞,6 连接上限单连接多路复用
请求头重复发送HPACK 压缩
优先级无流优先级与依赖
服务端推送无可主动推送资源(谨慎使用)

避坑:HTTP/2 要求所有请求头小写、且不再支持部分 HTTP/1.1 能力。若同时暴露明文 80 端口,不要在其上启用 http2(h2c 默认关闭)。

4. OCSP Stapling

4.1 为什么需要 OCSP

客户端校验证书是否被吊销,默认会向 OCSP 服务器发起查询,这会拖慢握手甚至单点故障。OCSP Stapling 由服务器定期抓取响应并"钉"在握手里发给客户端。

server {
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;
}

4.2 验证 Stapling 是否生效

openssl s_client -connect example.com:443 -status -servername example.com 2>&1 \
  | grep -A3 "OCSP response"
# 期望看到: OCSP Response Status: successful (0x0)
配置项作用
ssl_stapling on开启钉住响应
ssl_stapling_verify校验 OCSP 响应签名
ssl_trusted_certificate提供中间链供校验
resolverOCSP 域名解析

避坑:ssl_trusted_certificate 指向 chain.pem 而非 fullchain.pem;缺少 resolver 时 Stapling 会静默失败,务必用 s_client 实测确认。

5. 会话复用与性能

5.1 会话缓存与票据

server {
    ssl_session_cache   shared:SSL:10m;     # 共享缓存 10MB,约可存 4 万会话
    ssl_session_timeout 1d;
    ssl_session_tickets off;                # 关闭票据,用服务端缓存更可控
}
机制优点缺点
会话缓存(shared)同 worker 共享,防重协商多实例需共享存储
会话票据(ticket)无状态,适合多实例私钥泄露影响面大
无复用每连接全握手性能最差

5.2 握手性能优化清单

ssl_session_cache shared:SSL:20m;
ssl_session_timeout 4h;
ssl_session_tickets off;
ssl_early_data on;            # 0-RTT,仅 TLSv1.3,注意重放攻击风险

核心认知:会话复用把 TLS 握手中的"完整握手"降级为"缩短握手",是 HTTPS 性能的关键杠杆。开启 ssl_early_data(0-RTT)前必须评估重放攻击对业务的影响。

5.3 完整 HTTPS server 模板

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate         fullchain.pem;
    ssl_certificate_key     privkey.pem;
    ssl_trusted_certificate chain.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';
    ssl_prefer_server_ciphers on;

    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 valid=300s;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
}

这份模板把证书链、协议、套件、会话复用、Stapling 与 HSTS 一次性配齐,可直接作为生产基线。

6. HSTS 与重定向

6.1 全站 HTTPS 重定向

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

6.2 HSTS 强制 HTTPS

server {
    listen 443 ssl;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}
参数含义
max-age浏览器信任 HTTPS 的时长(秒)
includeSubDomains子域名一并强制
preload申请进入浏览器预加载列表
always对 4xx/5xx 也输出该头

避坑:HSTS 一旦下发,浏览器会拒绝访问该域名的明文 HTTP。务必在全部子域名都能提供 HTTPS 后再开启 includeSubDomains,否则子域会被"锁死"。

7. 证书管理与自动化

7.1 证书自动轮换

# certbot 续期并触发 Nginx 重载
certbot renew --quiet --deploy-hook "nginx -s reload"

7.2 验证与诊断命令

# 查看证书详情与有效期
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates -subject -issuer

# 查看支持的协议与套件
openssl s_client -connect example.com:443 -tls1_3 -servername example.com

7.3 常见故障排查

现象原因修复
安卓握手失败证书链缺中间 CA使用 fullchain.pem
扫描评分低协议或套件过旧收紧 ssl_protocols/ciphers
握手缓慢未开 Stapling/会话复用开启 OCSP Stapling + session cache
证书过期未配置自动续期certbot renew + reload hook
子域强制失败HSTS 覆盖范围过大先收敛子域再开 includeSubDomains

8. 总结

环节要点
证书链fullchain.pem 含中间 CA,私钥权限 600
协议TLSv1.2 + TLSv1.3,禁用旧版
套件ECDHE + AES-GCM/ChaCha20,前向保密
HTTP/2http2 on,ALPN 协商 h2
OCSPssl_stapling on + verify + resolver
会话复用shared 缓存 + 票据权衡
HSTSmax-age + includeSubDomains 谨慎开启
运维certbot 自动续期 + s_client 定期验证

HTTPS 加固完成后,流量已加密可信,但性能还有很大优化空间。下一篇将聚焦缓存与压缩,用 proxy_cache 与 gzip 把响应延迟进一步降下来。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「nginx」更多文章

  1. Nginx Ingress Controller:Kubernetes 云原生网关的路由、证书与金丝雀发布
  2. Nginx 监控与可观测性:stub_status 指标、Prometheus 集成与容量规划
  3. Nginx 静态资源与页面加速:零拷贝、缓存验证与 Brotli 压缩联动