3、OCSP协议实战:在线证书状态查询的核心机制

说到证书吊销,CRL 是基础,但 OCSP 才是真正在生产环境里扛大梁的协议。我最早接触 OCSP 是在一次金融系统的证书改造项目中,那时候 CRL 列表已经大到每次下载都要几十秒,客户端连接超时频发。后来切到 OCSP,问题才真正解决。

说白了,OCSP 就是「按需查询」。你拿到一张证书,不用下载整个黑名单,只问 CA 一句:「这张证书现在有效吗?」CA 回答「好」或「坏」。就这么简单。

3.1 OCSP 的工作原理

OCSP(Online Certificate Status Protocol)定义在 RFC 6960。它的核心角色有三个:

  • OCSP 客户端:通常是 TLS 客户端(浏览器、服务器),负责发起查询
  • OCSP 响应器:CA 或第三方部署的服务,负责返回证书状态
  • 证书主体:被查询的那张证书

工作流程其实就四步:

  1. 客户端拿到服务器证书后,提取证书序列号
  2. 客户端向 OCSP 响应器发送请求,包含证书序列号和颁发者信息
  3. OCSP 响应器查询数据库,返回状态(good、revoked、unknown)
  4. 客户端根据响应决定是否继续 TLS 握手

关键点:OCSP 响应必须由证书的颁发 CA 或受信任的响应器签名。客户端会验证响应签名,防止中间人篡改。

我在项目中遇到过一个问题:OCSP 响应器挂了怎么办?嗯,这就要说到 OCSP 的「软失效」和「硬失效」策略了。大部分浏览器默认是软失效——查不到就当证书有效。这其实是个安全妥协,但现实如此。

3.2 OCSP 请求与响应格式

OCSP 使用 ASN.1 编码,底层走 HTTP。说白了就是二进制数据包,但我们可以通过工具把它转成可读格式。

3.2.1 请求格式

一个典型的 OCSP 请求包含:

  • 协议版本:当前只有 v1
  • 请求列表:可以一次查多张证书
  • 扩展字段:比如 Nonce(防重放)

用 OpenSSL 模拟一个 OCSP 请求:

# 生成 OCSP 请求并发送
openssl ocsp -issuer ca.crt -cert server.crt -url http://ocsp.example.com -text

输出中你会看到类似这样的结构:

OCSP Request Data:
    Version: 1 (0x0)
    Requestor List:
        Certificate ID:
          Hash Algorithm: sha1
          Issuer Name Hash: 8C:3A:...
          Issuer Key Hash: A1:4B:...
          Serial Number: 0x12345678
    Request Extensions:
        Nonce: 0x9A3B...

这里要注意的是 Issuer Key Hash,它是 CA 公钥的哈希值,用来唯一标识颁发者。我曾经踩过一个坑:两个 CA 的 DN 相同但密钥不同,客户端用 DN 匹配导致查到了错误的响应器。

3.2.2 响应格式

OCSP 响应结构:

字段 说明 典型值
responseStatus 响应状态码 successful (0)
signatureAlgorithm 签名算法 sha256WithRSAEncryption
certs 响应签名证书(可选) OCSP 响应器证书
tbsResponseData 响应体 包含证书状态

响应体里的核心是 SingleResponse:

OCSP Response Data:
    Produced At: Apr 10 12:00:00 2025 GMT
    Responses:
        Certificate ID:
          Serial Number: 0x12345678
        Cert Status: revoked
        Revocation Time: Apr 1 10:00:00 2025 GMT
        This Update: Apr 10 12:00:00 2025 GMT
        Next Update: Apr 17 12:00:00 2025 GMT

三种状态的含义:

  • good:证书当前有效
  • revoked:证书已被吊销,附带吊销时间
  • unknown:响应器不知道这张证书(通常意味着证书不是该 CA 颁发的)

注意:OCSP 响应有有效期(This Update / Next Update)。客户端应该缓存响应,但不要超过 Next Update。我见过有些客户端无限缓存 OCSP 响应,证书吊销了还在用旧缓存,这等于白查。

3.3 OCSP Stapling 技术

OCSP 有个明显的性能问题:每次 TLS 握手都要额外发一个 HTTP 请求。用户多的时候,OCSP 响应器扛不住,客户端也等得心焦。

OCSP Stapling 就是来解决这个问题的。说白了,让服务器替客户端去查 OCSP,然后把结果「钉」在 TLS 握手消息里一起发给客户端。

3.3.1 工作原理

对比一下两种模式:

特性 传统 OCSP OCSP Stapling
谁发起查询 客户端 服务器
查询时机 每次 TLS 握手 服务器定时缓存
额外延迟 有(HTTP 请求) 无(握手内完成)
隐私保护 差(CA 知道谁在查) 好(CA 只知道服务器)
服务器负载 低 中(需定期刷新)

我个人习惯在生产环境强制开启 OCSP Stapling。原因很简单:用户体验好,隐私也更好。CA 不会知道每个用户的访问记录,只知道你的服务器在定期刷新。

3.3.2 Nginx 配置实战

Nginx 开启 OCSP Stapling 的配置:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    # 开启 OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # 指定 CA 证书链(用于验证 OCSP 响应签名)
    ssl_trusted_certificate /etc/nginx/certs/ca-chain.crt;

    # OCSP 响应器地址(可选,默认从证书中提取)
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

配置完成后,可以用 OpenSSL 验证:

openssl s_client -connect example.com:443 -status -tlsextdebug

输出中如果看到 OCSP response 字段,说明 Stapling 生效了。

避坑指南:我曾经在配置时忘了加 ssl_trusted_certificate,结果 Nginx 无法验证 OCSP 响应签名,Stapling 一直不生效。检查日志才发现是证书链没配全。记住,这个文件要包含完整的 CA 链,不只是服务器证书。

3.3.3 Must-Staple 扩展

有些证书会带上一个特殊扩展:Must-Staple(OID 1.3.6.1.5.5.7.1.24)。这个扩展告诉客户端:「这张证书必须使用 OCSP Stapling,否则不要信任我。」

为什么要这个?因为传统 OCSP 有软失效问题——查不到就当有效。攻击者可以阻断客户端的 OCSP 查询,让客户端以为证书有效。Must-Staple 强制服务器必须提供 Stapling 响应,否则握手失败。

申请 Must-Staple 证书的方法:

# 生成 CSR 时添加 Must-Staple 扩展
openssl req -new -newkey rsa:2048 -nodes -keyout server.key \
  -out server.csr -addext "tls-feature=status_request"

嗯,这里要注意:不是所有 CA 都支持 Must-Staple。申请前先确认 CA 的能力。

3.4 OCSP 与 CRL 的对比

你可能会问:有了 OCSP,还要 CRL 干嘛?

我的看法是:两者互补,不是替代关系。

维度 CRL OCSP
数据量 全量列表,可能很大 单条查询,数据小
实时性 取决于 CRL 更新周期 接近实时
网络开销 定期下载大文件 每次查询小请求
隐私 差(下载时暴露身份) 传统 OCSP 差,Stapling 好
离线可用 可以缓存 需要在线
部署复杂度 低 中(需要响应器)

实际生产环境中,我建议:

  • 客户端优先使用 OCSP Stapling
  • 降级时使用传统 OCSP
  • CRL 作为最后兜底

这样既保证了性能,又不会因为单点故障导致全部失效。

3.5 本章核心流程图

下面这张图展示了 OCSP 和 OCSP Stapling 的完整交互流程,方便你对比理解:

OCSP 与 OCSP Stapling 交互流程对比 传统 OCSP 流程 TLS 客户端 服务器 OCSP 响应器 ① TLS 握手 ② 返回证书 ③ OCSP 请求 ④ OCSP 响应 OCSP Stapling 流程 TLS 客户端 服务器 OCSP 响应器 ① 定时查询 ② 缓存响应 ③ TLS 握手 ④ 证书 + OCSP 响应 客户端无需额外请求,OCSP 响应内嵌在握手消息中

从图上可以清楚看到:传统 OCSP 需要客户端多走一步 HTTP 请求,而 Stapling 把这一步挪到了服务器端,客户端零额外延迟。

一句话总结:OCSP 解决了 CRL 的实时性和带宽问题,OCSP Stapling 又解决了 OCSP 的性能和隐私问题。三者配合使用,才能构建一个健壮的证书吊销验证体系。