1. OCSP 协议基础
聊 OCSP 日志异常检测之前,咱们得先把 OCSP 协议本身吃透。你想想看,如果一个告警说你有一堆 OCSP 响应是 unknown,但你连 OCSP 是怎么工作的都不清楚,那排查就像瞎子摸象。
OCSP 全称是 Online Certificate Status Protocol,在线证书状态协议。说白了,它就是用来替代 CRL(证书吊销列表)的。CRL 那个列表越积越大,下载一次能愁死人。OCSP 则按需查询,效率高得多。我记得刚入行时做过一个 PKI 项目,CRL 缓存没配好,每次握手都去拉全量列表,客户端直接 timeout。后来切到 OCSP,响应时间从几秒降到几十毫秒。
1.1 工作原理
OCSP 的交互模式很简单:客户端拿着服务器证书,向 OCSP 响应器发一个请求:「这个证书现在状态怎么样?」响应器去查 CA 的数据库,然后返回一个签名过的状态结论。
注意这里有个关键点——响应器必须对结果做数字签名。如果没有签名,任何人都可以伪造响应说「这个证书已被吊销」,那整个 HTTPS 体系就塌了。我在项目里见过有人为了省事,把 OCSP 响应缓存直接暴露在外网,没校验签名,结果被中间人攻击,几个域名都被标记为 revoked,用户大面积报错。
下图是 OCSP 协议的完整调用流程,我建议你把这个图刻在脑子里:
1.2 请求与响应格式
OCSP 请求其实就是一个封装在 ASN.1 结构里的数据包,用 DER 编码。实际抓包时你看不到明文「status=good」,得用 openssl 或 Wireshark 解。我工作中最常用的就是 openssl ocsp 命令直接模拟请求,方便排障。
我总结了一张常用字段表,你排查日志异常时大概率会用到:
| 元素 | 请求中 | 响应中 | 说明 |
|---|---|---|---|
| tbsRequest | ✔ | ✘ | 包含待查询的证书列表 |
| certID | ✔ | ✔ | 证书哈希 + 颁发者信息 |
| hashAlgorithm | ✔ | ✔ | 通常是 SHA-1 或 SHA-256 |
| issuerNameHash | ✔ | ✔ | 颁发者 DN 的哈希 |
| issuerKeyHash | ✔ | ✔ | 颁发者公钥的哈希 |
| serialNumber | ✔ | ✔ | 证书序列号,你查日志主要看它 |
| nonce | 可选 | 可选 | 防重放,日志里如果 nonce 不匹配就是攻击信号 |
| signatureAlgorithm | ✘ | ✔ | 响应签名算法 |
| signature | ✘ | ✔ | 数字签名值,长度常为 256 或 512 字节 |
| certs | ✘ | 可选 | 响应器额外附带的证书链 |
实战小点:日志分析时,重点关注 serialNumber、nonce 和 signature 字段。如果请求的 serialNumber 不在 CA 范围内,响应可能会返回 unknown。我曾经碰到过一个线上事故:某个老旧脚本把证书序列号拼成了十六进制大写,而 OCSP 响应器要求小写,结果所有请求都返回 unknown,导致业务中断了半小时。
1.3 三种响应类型
OCSP 响应只有三种结果,没有「maybe」或者「pending」那种模棱两可的状态:
- good – 证书当前有效,未被吊销。注意这里不代表证书一定可信,只是说它在 CA 这边没被标记吊销。
- revoked – 证书已被吊销。日志里出现这个,要么是真的证书有问题,要么是响应被篡改或时间偏差。
- unknown – 响应器不知道这个证书的状态。原因很多:证书序列号不对、CA 不认这个签发者、响应器没同步到最新数据等。
这三种状态在日志里很好识别,但坑也最多。举个例子:如果某个客户端大量收到 unknown,千万别直接怀疑它是攻击——先检查一下请求里的 issuerNameHash 是否和响应器的预期一致。我曾经花了一天时间追一个诡异问题,最后发现是 openssl 版本升级后默认哈希算法从 SHA-1 变成了 SHA-256,两边没对齐,全成了 unknown。
1.4 OCSP Stapling
传统 OCSP 有个性能问题:每次 TLS 握手,浏览器都要额外去 OCSP 响应器查一次,增加了延迟。而且如果 OCSP 响应器挂了,浏览器可能直接拒绝连接。
Stapling 技术就是让服务器自己「事先把 OCSP 响应拿回来」,然后在 TLS 握手时直接塞给客户端。客户端不需要额外发起请求,延迟低,而且服务器可以缓存响应并定期更新。我记得第一次在生产环境配 Nginx 的 ssl_stapling 时,手抖把 stapling responder 地址写成了测试环境,结果上线后所有访客都看到证书 revoked……
我的建议:Stapling 日志里会多一个 OCSPResponseStatus: successful 的字段,而缓存命中时可能没有新的查询记录。如果你做异常检测,要注意区分「客户端直接请求 OCSP 响应器」和「通过 Stapling 获得响应」这两种日志来源,它们的特征完全不同。
另外,Stapling 虽然好,但响应必须定期更新。如果服务器证书已经换了,但 Stapling 缓存还没过期,客户端会拿到旧的 good 响应,直到下一个更新周期才纠正——这个窗口期就是攻击者可以利用的空子。我建议日志监控里加一个指标:每一次 Stapling 更新后,记录新的 thisUpdate 时间,如果和上一个时间差超过 CA 推荐的更新间隔(通常 4 小时),就触发告警。
曾经有个坑:某客户把 Stapling 的响应缓存时间设成了 24 小时,结果 CA 在中午吊销了一批证书,他们的服务器直到第二天才刷新到 revoked 状态。这期间所有访问该站点的客户端都认为证书有效。所以日志里如果发现 Stapling 响应中 thisUpdate 时间距当前超过 6 小时,建议标记为可疑。