什么是 OCSP Stapling

OCSP Stapling(正式名称为 TLS Certificate Status Request)是一种 TLS 扩展机制,允许服务端在 TLS 握手过程中主动向客户端提供证书的状态信息,而无需客户端自行向 CA 的 OCSP 响应服务器发起查询。

它的核心价值在于:将证书状态验证的责任从客户端转移到服务端,同时保护用户隐私、提升连接速度。

为什么需要 OCSP Stapling

要理解 OCSP Stapling 的价值,先看没有它时证书撤销检查的三种方式。

方式一:CRL(证书吊销列表)

CA 定期发布一个包含所有已吊销证书序列号的列表(CRL),客户端下载后自行检查。

1
2
# 查看 CRL 分布点(CRL Distribution Points)
openssl x509 -in cert.pem -noout -text | grep -A2 "CRL Distribution"

问题很明显:CRL 文件会随着时间不断增长,下载和解析开销越来越大。即使使用增量 CRL(Delta CRL),也难以应对大规模部署。

方式二:OCSP(在线证书状态协议)

客户端直接向 CA 的 OCSP 响应服务器发送查询,获取单张证书的实时状态。

1
2
3
# 提取证书的 OCSP 响应器 URL
openssl x509 -in cert.pem -noout -ocsp_uri
# 示例输出: http://ocsp.example.com

OCSP 解决了 CRL 体积膨胀的问题,但带来了新的痛点:

  • 隐私泄露:CA 的 OCSP 服务器能记录每个用户的访问行为
  • 性能损耗:额外的网络请求增加 TLS 握手延迟
  • 可用性风险:OCSP 服务器宕机时,客户端面临"软失败"(放行可疑证书)还是"硬失败"(阻断所有连接)的两难选择
  • 浏览器兼容:各浏览器对 OCSP 结果的处理策略不一致

方式三:OCSP Stapling(最优解)

服务端定期从 CA 获取 OCSP 响应并缓存,在 TLS 握手时将其"装订"(Staple)到 ServerHello 消息中一并发送给客户端。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  客户端                          服务端
    |                               |
    |------- ClientHello ---------->|
    |   (包含 status_request 扩展)   |
    |                               |
    |<------ ServerHello -----------|
    |   (包含 CertificateStatus)     |
    |                               |
    |<------ Certificate -----------|
    |<------ ServerHelloDone -------|
    |                               |

一次握手,零额外请求。

OCSP Stapling 工作原理

扩展协商

客户端在 ClientHello 中发送 status_request 扩展(TLS Extension Type 5),声明自己支持 OCSP Stapling。

1
2
# 使用 openssl s_client 查看服务端返回的 TLS 扩展
echo | openssl s_client -connect example.com:443 -status -tlsextdebug 2>&1 | grep -i "status\|OCSP"

服务端获取 OCSP 响应

服务端通过 openssl ocsp 命令(或内置模块)向 CA 的 OCSP 响应器发起请求:

1
2
3
4
5
6
7
# 构造并发送 OCSP 请求到 CA 响应器
openssl ocsp \
  -issuer ca-chain.pem \
  -cert server.pem \
  -url http://ocsp.example.com \
  -resp_text \
  -nonce

CA 返回签名的 OCSP 响应,包含证书状态(good / revoked / unknown)和时间戳。

响应装订

服务端将 OCSP 响应放入 CertificateStatus 消息,在握手阶段发送给客户端。客户端验证响应签名和时间有效性后,即可确认服务端证书未被吊销。

OCSP 响应解析

OCSP 响应是 ASN.1 编码的结构化数据,可以通过 OpenSSL 解析:

1
2
# 将 OCSP 响应保存为文件后解析
openssl ocsp -respin ocsp-response.der -resp_text

典型响应内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: C = US, O = Let's Encrypt, CN = R3
    Produced At: Apr 20 14:30:00 2026 GMT
    Responses:
    Certificate ID:
      Hash Algorithm: sha1
      Issuer Name Hash: SHA1 Hash...
      Issuer Key Hash: SHA1 Hash...
      Serial Number: 04AB...
    Cert Status: good
    This Update: Apr 20 14:30:00 2026 GMT
    Next Update: Apr 27 14:30:00 2026 GMT

关键字段说明:

  • Cert Statusgood(正常)、revoked(已吊销)、unknown(未知)
  • This Update:OCSP 响应生成时间
  • Next Update:响应有效期截止,超过此时间后响应失效
  • Responder Id:响应签名者的身份信息

Nginx 配置 OCSP Stapling

基础配置

Nginx 启用 OCSP Stapling 的配置非常简洁:

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

    ssl_certificate     /etc/ssl/certs/example.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/private/example.com/privkey.pem;

    # 启用 OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # 指定信任的 CA 证书链(用于验证 OCSP 响应签名)
    ssl_trusted_certificate /etc/ssl/certs/example.com/ca-chain.pem;

    # 可选:指定 OCSP 响应器(覆盖证书中嵌入的 URL)
    # ssl_stapling_responder http://ocsp.example.com;

    # DNS 解析器(Nginx 需要解析 OCSP 响应器域名)
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

关键配置说明

ssl_stapling on 启用 OCSP Stapling。Nginx 会在启动时自动从证书的 AIA 扩展中提取 OCSP 响应器 URL,首次获取响应后缓存。

ssl_stapling_verify on 启用 OCSP 响应验证。Nginx 会验证响应的签名是否来自可信的 CA,防止伪造的 OCSP 响应。

ssl_trusted_certificate 指定 CA 证书链文件,用于验证 OCSP 响应的签名。注意:这不是服务器证书链,而是签发服务器证书的 CA 证书(中间 CA + 根 CA)。

resolver Nginx 需要 DNS 解析器来查询 OCSP 响应器的域名。如果 OCSP URL 使用 IP 地址则不需要此项。

配置验证

1
2
# 检查 Nginx 配置语法
nginx -t

Let’s Encrypt 示例

对于 Let’s Encrypt 证书,ssl_trusted_certificate 应该包含 ISRG Root X1 根证书和 R3 中间证书:

1
2
3
# 下载 Let's Encrypt 信任链(ISRG Root X1 + R3)
# 通常可以使用 certbot 生成的 chain.pem 或者手动拼接
cat /etc/letsencrypt/live/example.com/chain.pem > /etc/ssl/certs/example.com/ca-chain.pem

验证 OCSP Stapling 是否生效

方法一:使用 OpenSSL s_client

1
2
# -status 参数请求服务端返回 OCSP Stapling 响应
echo | openssl s_client -connect example.com:443 -status 2>&1 | grep -A20 "OCSP response"

成功启用的输出示例:

1
2
3
4
5
6
7
8
9
OCSP response:
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    ...
    Cert Status: good
    This Update: Apr 20 14:30:00 2026 GMT
    Next Update: Apr 27 14:30:00 2026 GMT

未启用的输出示例:

1
2
3
OCSP response:
======================================
No Response found.

方法二:查看 TLS 扩展调试信息

1
echo | openssl s_client -connect example.com:443 -status -tlsextdebug 2>&1 | grep -i "status_request"

输出中包含 status_request 表示客户端请求了 stapling,服务端响应中包含 CertificateStatus 表示 stapling 生效。

方法三:使用 curl

1
2
# curl 本身不直接显示 OCSP Stapling 状态,但可以结合 -v 查看握手详情
curl -vI https://example.com 2>&1 | grep -i "ocsp\|stapling"

大多数情况下,openssl s_client -status 是最可靠的验证方式。

常见问题排查

问题一:OCSP 响应获取失败

现象: Nginx 日志中出现 OCSP_basic_verify() failedOCSP responder not responding

排查步骤:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 1. 确认证书中包含 OCSP 响应器 URL(AIA 扩展)
openssl x509 -in /etc/ssl/certs/example.com/fullchain.pem -noout -ocsp_uri

# 2. 手动测试 OCSP 响应器连通性
openssl ocsp \
  -issuer /etc/ssl/certs/example.com/ca-chain.pem \
  -cert /etc/ssl/certs/example.com/fullchain.pem \
  -url $(openssl x509 -in /etc/ssl/certs/example.com/fullchain.pem -noout -ocsp_uri) \
  -resp_text 2>&1 | head -20

# 3. 检查 DNS 解析
nslookup $(openssl x509 -in /etc/ssl/certs/example.com/fullchain.pem -noout -ocsp_uri | sed 's|http://||' | cut -d'/' -f1)

常见原因:

  • OCSP 响应器被防火墙阻断
  • DNS 解析失败(检查 resolver 配置)
  • ssl_trusted_certificate 配置错误或文件不存在

问题二:OCSP Stapling 不生效

现象: openssl s_client -status 返回 No Response found

排查步骤:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 1. 检查 Nginx 错误日志
tail -f /var/log/nginx/error.log | grep -i ocsp

# 2. 确认配置项拼写正确
nginx -T 2>&1 | grep -i "ssl_stapling"

# 3. 重新加载 Nginx 配置
nginx -s reload

# 4. 等待 OCSP 响应缓存(首次获取可能需要几秒)
sleep 5 && echo | openssl s_client -connect example.com:443 -status 2>&1 | grep -A5 "OCSP response"

问题三:OCSP 响应过期

OCSP 响应有有效期(通常 7 天)。Nginx 会在响应接近过期时自动重新获取。但如果 OCSP 响应器持续不可用,过期的响应将被停止提供。

1
2
# 检查 Nginx 日志中是否有 OCSP 响应过期的警告
grep -i "ocsp.*expir" /var/log/nginx/error.log

OCSP Stapling vs OCSP Must-Staple

这两个概念相关但有区别:

特性 OCSP Stapling OCSP Must-Staple
定义 TLS 扩展机制 证书扩展(OCSP Must-Staple extension)
强制力 服务端可选 浏览器强制要求
失败行为 客户端可能回退到普通 OCSP 浏览器直接拒绝连接

OCSP Must-Staple 是证书中的一个扩展(OID: 1.3.6.1.5.5.7.1.24),声明该证书必须通过 OCSP Stapling 验证状态。如果服务端没有提供有效的 Stapling 响应,浏览器会拒绝连接。

生成包含 Must-Staple 扩展的 CSR:

 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
# 创建包含 OCSP Must-Staple 扩展的配置文件
# DER:30:03:02:01:05 表示 SEQUENCE { INTEGER 5 },即 status_request
cat > must-staple.cnf << 'EOF'
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req

[dn]
CN = example.com

[v3_req]
1.3.6.1.5.5.7.1.24 = DER:30:03:02:01:05
EOF

# 生成 CSR
openssl req -new -newkey rsa:2048 -nodes \
  -keyout example.com.key \
  -out example.com.csr \
  -config must-staple.cnf

# 验证 CSR 中包含 Must-Staple 扩展
openssl req -in example.com.csr -noout -text | grep -A1 "TLS Feature"

输出中的 status_request 即表示 Must-Staple 扩展已正确嵌入。

注意: 启用 OCSP Must-Staple 需要谨慎。如果服务端的 Stapling 配置出现问题,用户将完全无法访问网站。建议先确保 OCSP Stapling 稳定运行后再考虑启用 Must-Staple。

性能考量

OCSP Stapling 对性能的影响:

  • 服务端:首次启动时向 CA 获取一次 OCSP 响应,之后按缓存策略自动刷新。对服务端性能影响极小。
  • 客户端:零额外请求,TLS 握手延迟不增加。
  • 网络:减少客户端到 CA 的往返,降低整体网络负载。

实测数据表明,启用 OCSP Stapling 后,首次 TLS 握手时间可减少 100-500ms(取决于客户端到 CA OCSP 响应器的网络延迟)。

总结

OCSP Stapling 是 TLS 生态中一项优雅的设计:它将证书状态验证的负担从客户端转移到服务端,同时解决了隐私、性能和可用性问题。

核心要点:

  • Nginx 配置只需三行:ssl_stapling onssl_stapling_verify onssl_trusted_certificate
  • 使用 openssl s_client -status 快速验证是否生效
  • 确保 DNS 解析和 OCSP 响应器连通性正常
  • OCSP Must-Staple 提供更强保障,但需要谨慎启用

参考来源