PKI与证书体系

在做OCSP异常检测之前,你必须先搞清楚一个底层问题:证书到底是怎么信任的?说白了,整个HTTPS、代码签名、邮件加密,背后都靠PKI这张大网撑着。

我当年刚接触PKI时,觉得这东西就是个“CA发证书”的简单流程。直到有一次排查线上TLS握手失败,才发现证书链、CRL、OCSP这三者配合不好,能让你排查到怀疑人生。今天咱们就把这张网拆开揉碎。

公钥基础设施构成

PKI不是单一软件,是一套人+流程+技术的组合。记住下面这几个核心角色就行:

  • 证书颁发机构(CA) – 签发和撤销证书的“权威法院”。
  • 注册机构(RA) – 负责验证申请者身份,把审核结果告诉CA。
  • 证书库(Repository) – 存放已签发证书和CRL的地方,通常用LDAP或HTTP。
  • 证书持有者(End Entity) – 拿着证书的人或设备,比如你的浏览器或服务器。
  • 依赖方(Relying Party) – 需要验证证书的人,比如你浏览器在访问HTTPS网站时。

你想想看,这五个角色配合起来,才形成一个完整的信任闭环。我在某电商公司审计时,发现他们RA环节几乎没人管,身份验证全凭邮件确认,结果被中间人伪造了证书。嗯,后来我们强制加了视频验证和生物特征,才算堵上漏洞。

个人习惯:每次看CA配置时,我会先查RA的操作日志。RA如果写“急事特批”这种备注,基本就是风险信号。

X.509证书结构

RFC 5280定义的X.509 v3证书,说白了就是一个结构化的数据包。你用openssl x509 -text一看,里面字段至少二十多个。但关键的就这几块:

字段典型内容我的踩坑提醒
版本号v3(0x02)要是v1或v2,基本是老古董,别用。
序列号CA生成的唯一号码我曾经碰到过序列号重复,那家CA的数据库废了。
签名算法sha256WithRSAEncryption如果写md5或sha1,立即报警。
颁发者(Issuer)C=CN, O=某CA, CN=Root CA注意拼写错误,我见过Issuer和Subject拼反的。
主体(Subject)C=US, O=Google, CN=*.google.com通配符证书不能滥用,我见过*.*.com这种荒唐写法。
有效期notBefore / notAfter过期证书是OCSP日志里的常客。
公钥RSA 2048 / ECC P-256密钥长度低于2048的,我建议直接拒绝。
扩展Key Usage, Extended Key Usage, Subject Alt Name等扩展缺失会导致证书被滥用,比如把服务端证书当代码签名用。

有一个细节我特别在意:授权密钥标识符(Authority Key Identifier)。它指向颁发者的Subject Key Identifier,是构建证书链的关键线索。你要是用openssl验证时提示“unable to get local issuer certificate”,多半是这个字段对不上。

CRL vs OCSP:离线PKI vs 在线PKI

证书被吊销(比如私钥泄露、员工离职),必须让依赖方知道。传统方案是证书吊销列表(CRL),现代方案是在线证书状态协议(OCSP)。两者的区别,我用一张表说清楚:

对比项CRLOCSP
数据获取方式定时下载整张列表实时查询单张证书
网络请求1次请求拿到所有吊销证书每张证书都要单独查询
时效性取决于CRL更新周期(可能数天)实时响应(通常秒级)
隐私性不暴露查询哪个证书服务器能看到你在查谁(所以出现OCSP stapling)
流量开销列表可能几MB,对移动端不友好请求响应几十字节,非常轻量
服务器负载CDN扛得住,但更新是全量并发高时容易打爆OCSP响应器

我在银行做审计时,亲眼见过一个CA的CRL更新频率是每周一次。周二私钥泄露,直到下周一才被吊销,中间五天黑客拿了证书乱签名。从那以后,我强烈建议所有生产环境必须启用OCSP,并且配合Must-Staple扩展。

警告:OCSP响应本身也要签名,否则中间人可以伪造“证书有效”。验证OCSP响应时,必须检查签名、nonce(如果用了)和ThisUpdate/NextUpdate。我曾经遇到一个案例,OCSP响应器的证书过期了,所有OCSP响应都被客户端当成无效,导致全线服务中断。

证书链验证过程

验证一个终端证书是否可信,不是只看它本身,而是要沿着证书链一直追到信任锚点(通常是预置在操作系统或浏览器里的根证书)。流程很简单,但坑很多:

  1. 构建链 – 从终端证书开始,根据Issuer字段找到签发者证书,再往上,直到一个自签名根证书或你信任的锚点。
  2. 验证签名 – 每一级都用上一级的公钥验证下一级的签名。签名不匹配,直接报错。
  3. 检查有效期 – 每一张证书的notBefore/notAfter必须包含当前时间。注意:根证书通常长期有效,中间证书可能就2-3年。
  4. 检查吊销状态 – 可以用CRL或OCSP查询每张证书(除了根证书,因为它自签名且无上级吊销它)。
  5. 检查关键扩展 – 比如Basic Constraints必须标识CA权限,Key Usage必须包含keyCertSign等。

这里有个容易忽视的点:证书链不一定只有一条路径。比如同一张终端证书可能被两个不同的CA签发(交叉认证)。我曾经在排查一个SSL握手失败时,发现客户端只带了一条链,而服务器信任的根在另一条链上,花了三小时才定位到。后来我写了个脚本,每次部署前自动打印所有可能的Certificate Path。

避坑指南:我曾经在log日志里看到大量“certificate verify failed”却查不出原因。最后用openssl s_client -showcerts -verify_return_error模拟全链路,才发现是中间证书的OCSP URL写成了http而不是https,非加密通道被劫持了。所以,请一定检查证书里的Authority Information Access (AIA)字段。

下面这张图总结一下PKI的完整体系,也是我们做OCSP日志异常检测时必须刻在脑子里的结构:

PKI体系架构与证书链验证流程 证书颁发机构 (CA) 签发 & 吊销证书 注册机构 (RA) 身份审核 证书库 CRL / 证书存储 审核请求 发布证书 终端实体 服务器 / 客户端 依赖方 浏览器 / 验证方 出示证书 OCSP响应器 实时状态查询 吊销通知 OCSP请求 证书链验证流程(由下至上) ① 终端证书 → ② 中间CA证书 → ③ 根CA证书 每个环节检查:签名有效、时间有效、未吊销 根证书必须位于本地信任存储(Trust Store) OCSP插桩位置 在验证②和③时,可发起OCSP查询吊销状态 OCSP响应日志应记录:查询时间、响应状态、签名完整性

有了这张图,再看OCSP日志就好办了。你每天会看到大量依赖方→OCSP响应器的请求:状态、时间、证书序列号、响应签名。我们后续课程就是要从这些日志里抓出“状态异常”、“响应延迟”、“伪造响应”等特征。

最后说一句:了解PKI不是为了考试,而是为了看懂异常。你在日志里看到“Unknown CA”或者“Certificate has expired”,如果脑子里立刻能浮现出上面那张图和证书结构,定位速度至少快一倍。