1. OCSP协议概述
1.1 为什么需要OCSP?
先问个问题:你访问一个 HTTPS 网站时,浏览器怎么知道对方的证书没有被吊销?
传统做法是去下载一份「证书吊销列表」(CRL)。嗯,这个列表会越来越大,每次都得全量拉取。我记得早期在给银行做 PKI 项目时,客户端同步 CRL 经常超时,用户那边证书明明有效,却因为列表没更新而被拦住了。那个场景至今印象深刻。
OCSP(在线证书状态协议)就是来解决这个痛点的。它允许客户端**实时查询**某一特定证书的当前状态:good(正常)、revoked(已吊销)或 unknown(未知)。说白了,它只问一张证书,不拉整个黑名单,轻巧得多。
1.2 OCSP工作原理
OCSP 的工作流程其实很简洁,我把它拆成四步:
- 客户端发起请求:浏览器或服务器构造一个 OCSP 请求,里面包含待查证书的序列号、颁发者信息等。
- OCSP 响应器接收:响应器(通常由 CA 搭建)收到请求后,去自己的数据库查这个证书的当前状态。
- 签名响应:响应器把查到的结果(good/revoked/unknown)加上时间戳,用自己的私钥签名,返回给客户端。
- 客户端验证签名:客户端拿到响应后,先验证签名是否合法、响应是否新鲜(时间窗口内),然后根据状态决定是否继续连接。
你可能会问:响应器怎么保证响应不被篡改?答案就是数字签名。响应必须用 CA 或授权响应器的私钥签名,客户端再拿对应的公钥验签。这套机制保证了响应的完整性和可追溯性。
1.3 OCSP vs CRL:一张表说清楚
| 对比维度 | OCSP | CRL |
|---|---|---|
| 查询粒度 | 单张证书 | 全量列表(包含所有吊销证书) |
| 实时性 | 高(实时查询) | 低(取决于 CRL 更新周期,通常几小时到几天) |
| 网络开销 | 请求/响应都很小(几百字节) | 全量列表可能很大(几 MB 甚至更大) |
| 隐私风险 | 暴露了被查的证书信息(但可通过扩展缓解) | 不暴露查询目标(因为所有人都拉同一份列表) |
| 可靠性依赖 | 依赖 OCSP 响应器的可用性 | 依赖 CRL 分发点(CDP)的可用性 |
| 典型应用 | 浏览器在线验证、TLS 握手 | 离线验证、邮件签名、代码签名 |
1.4 一个典型交互流程
下面这张 SVG 图展示了 OCSP 的基本交互过程,以及它与 CRL 模式的核心区别。左侧是传统的 CRL 拉取,右侧是 OCSP 实时查询。
从图中可以看出,CRL 是「定期拉全量」,OCSP 是「按需查单张」。我在实际项目中遇到过一件倒霉事:某个客户的 CRL 更新周期是 24 小时,结果证书被吊销后,外部系统拿着旧 CRL 验证通过了……那次事故之后,那个客户把所有面向互联网的接口全都切到了 OCSP 上。
nextUpdate 或时间戳过期,客户端不应信任该响应。我个人习惯在代码中强制校验 thisUpdate 和 nextUpdate 的时间差,超过 15 分钟直接判定 unknown 并走软失效降级。
1.5 一个小实验:抓住 OCSP 流量
你可以用 Wireshark 抓包看看真实的 OCSP 请求长什么样。打开浏览器访问任何 HTTPS 网站(比如百度),过滤 ocsp 或 tcp.port==80(某些 OCSP 走 80 端口)。你会看到类似这样的请求头和响应:
GET /ocsp/xxxxxxxx HTTP/1.1
Host: ocsp.example.com
Content-Type: application/ocsp-request
响应则是一段 ASN.1 编码的 DER 数据,里面包含签名和时间戳。嗯,乍一看全是二进制,但用 openssl 可以解析:
openssl ocsp -noverify -resp_text -respin /tmp/ocsp_response.der
自己动手试试看,我保证你能直观理解 OCSP 的结构。