OCSP Stapling 工作原理
说起 OCSP Stapling,其实它要解决一个很实际的问题——验证证书时,客户端自己去 OCSP 响应器查状态,效率太低了。我早年做 HTTPS 优化时就发现,光 OCSP 查询这一项,就能让 TLS 握手时间翻倍。后来才搞明白,Stapling 就是把 OCSP 响应直接“钉”在证书上,交给服务器代劳。
TLS 握手中的角色转换
正常的 TLS 握手流程,客户端收到服务端证书后,自己去找 OCSP 响应器问这张证书有没有被吊销。这有几个明显的问题:
- 额外开销:客户端得多发一次 HTTP 请求,尤其移动端网络差,影响很大。
- 隐私泄露:OCSP 响应器知道你访问了哪个站点。
- 单点故障:OCSP 响应器挂了,浏览器可能直接拒绝连接,或者干脆忽略验证。
Stapling 的思路正好反过来——证书状态的查询工作,由服务端来做。服务端定期从 CA 拉取 OCSP 响应,缓存在本地。等到客户端发起 TLS 握手时,服务端直接在握手过程中把这个响应“塞”给客户端。
我个人习惯把这个过程理解为:「服务端帮你去柜台盖了个章,然后把盖章的结果当场递给你看」。你不需要自己跑一趟,既省时间又防作伪。
Certificate Status Request 扩展
这个机制能工作,全靠 TLS 协议里的一个扩展——status_request(也叫 Certificate Status Request)。它定义在 RFC 6066 里。流程如下:
- 客户端声明:在 ClientHello 消息中带上
status_request扩展,表示「我支持 OCSP Stapling,请直接把响应给我」。 - 服务端响应:服务端看到这个扩展后,在 Certificate 消息之后,直接捎带一个 CertificateStatus 消息,里面就是缓存的 OCSP 响应。
- 客户端验证:客户端收到后,校验这个响应的签名是否来自 CA,以及响应中的序列号是否跟证书一致。
服务器如何缓存 OCSP 响应
服务端从 CA 的 OCSP 响应器拉取响应后,不会每次都重新请求。它会缓存一段时间,这个时间由 OCSP 响应里的 nextUpdate 字段控制。一般来说,CA 颁发的 OCSP 响应有效期是 4 到 7 天。但实际情况要复杂很多:
- 响应有效期太短:有些 CA 只给 1 小时有效期,服务端就得频繁拉取,压力不小。
- 响应有效期太长:如果证书被紧急吊销,客户端可能在有效期内拿到一个「未吊销」的旧响应。
我曾经在线上遇到过一个问题——某个 CA 的 OCSP 响应有效期是 7 天,但证书第二天就被吊销了。结果那 7 天内,所有使用 Stapling 的客户端都认为证书正常。嗯,这里要注意,Stapling 只是一个优化手段,它不能替代 CRL 或者实时 OCSP 查询。
一张图看懂流程
下面这张图我画了个简化流程,把 Stapling 和传统 OCSP 的核心区别放在一起对比。
ssl_stapling 和 ssl_stapling_verify。然后用 OpenSSL 的 s_client 命令加 -status 参数检查一下,看能不能拿到 OCSP 响应。我记得有人问过我「为什么开启后没效果」,其实就是忘了配 ssl_trusted_certificate 链,导致客户端无法验证。
合规检查的落脚点
理解了工作原理后,你会发现合规检查其实就在以下几个点上:
| 检查项 | 说明 | 常见问题 |
|---|---|---|
| 扩展声明 | 客户端是否发送 status_request 扩展 | 某些旧版浏览器/库不发 |
| 响应缓存 | 服务端是否正确缓存并更新 OCSP 响应 | 缓存过期、更新策略错误 |
| 响应验证 | 客户端是否校验 Stapled 响应的签名和序列号 | 跳过验证等同虚设 |
| 错误处理 | 服务端拿不到 OCSP 响应时怎么处理 | 直接断开连接或降级为普通 OCSP |
说白了,Stapling 的核心就是让服务端分担客户端的验证负担。但如果你配置不到位,这个「分担」反而可能引入新的合规风险。我个人习惯在刚配置完时,用抓包工具看一眼 TLS 握手阶段有没有 CertificateStatus 消息,有就对了,没有就继续调。