4. TLS证书与PKI体系:CA、证书链、验证
聊到TLS,绕不开一个东西——证书。很多人觉得证书就是个加密文件,装上去就能用。其实没那么简单。我把证书比喻成“互联网身份证”,而PKI就是管理这套身份证的体系。今天咱们就把它掰开揉碎了讲清楚。
4.1 CA:谁来发这个证?
CA(Certificate Authority),说白了就是“发证的机构”。你想想看,如果每个人都能自己印身份证,那不乱套了吗?CA就是那个权威的、大家都信任的发证方。
CA的核心职责有三点:
- 身份验证——申请者得证明“我是谁”。CA会检查域名所有权、企业资质等。
- 签发证书——验证通过后,CA用自己私钥给申请者签名,生成证书。
- 吊销管理——证书过期、私钥泄露,CA要把它拉进黑名单(CRL或OCSP)。
CA也分等级。顶级CA叫“根CA”,它自己给自己签名(自签名)。但根CA的私钥是至宝,一般离线保存。日常签发工作,交给“中间CA”去做。为什么要这么干?万一中间CA出问题,回收它就行,根不受影响。
| CA类型 | 签名方式 | 安全级别 | 典型场景 |
|---|---|---|---|
| 根CA | 自签名 | 最高(离线) | 信任锚点 |
| 中间CA | 根CA签名 | 高(在线或半离线) | 日常签发 |
| 终端实体证书 | 中间CA签名 | 标准 | 服务器/客户端 |
4.2 证书链:从根到叶子
为什么会有“链”?因为单靠一个CA签名不够安全。证书链就是一条信任传递路径。一个典型的链长这样:根CA → 中间CA1 → 中间CA2 → 你的服务器证书。
我习惯把这个链想成“介绍人制度”。你(服务器证书)不认识客户,但你的介绍人(中间CA2)认识你。中间CA2的介绍人(中间CA1)也认识它。而中间CA1的介绍人(根CA)是大家都信任的人。客户验证时,就沿着这条线一路问上去,直到那个大家都认的根。
证书链的格式一般是PEM拼接。你可能会看到这样的文件:
-----BEGIN CERTIFICATE-----
(你的服务器证书的Base64编码)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中间CA1的证书)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中间CA2的证书)
-----END CERTIFICATE-----
顺序有讲究:叶子证书在最上面,中间CA依次往下排。根CA一般不放进去,它得在客户端受信任的根存储区里。
4.3 验证:信任怎么传递?
验证过程,其实就三步。但每一步都可能踩坑。
- 签名验证——用上级证书的公钥,解密当前证书的签名。能解开,说明内容没被改。
- 有效期检查——当前时间必须在证书的“有效期”范围内。过期、未生效都算失败。
- 吊销状态检查——查CRL或OCSP,确认证书没被提前撤销。
嗯,这里要注意:时间同步问题。我遇到过服务器时间快了一个小时,所有证书都显示“未生效”。折腾半天才发现是NTP没配好。所以在验证前,先把系统时间校准了。
你会问:如果根CA证书在客户端被信任,那怎么保证客户端没被骗?实际上,OS和浏览器会预装一批根证书。这些根证书来自全球公认的CA。如果你的CA不在这个列表里,客户端就会弹出“不信任”的警告。有些公司自建内部PKI,就得手动把这套根证书推到每个终端上。
我建议这么做:验证逻辑写清楚,不要只依赖库的默认行为。比如OpenSSL的验证有“自签名证书”模式,如果不加限制,随便找个自签证书它也能过。你肯定不希望正式环境下出现这种“信任一切”的情况。
4.4 避坑与实战建议
除了上面提到的链不完整、时间不同步,还有几个常见问题。
- 自签名证书的信任问题:测试环境用自签没问题,但生产环境千万别这么干。客户端不认,你就等着报错吧。实在要用自签,得把根证书导入客户端的信任存储。
- 证书域名匹配:CN(Common Name)和SAN(Subject Alternative Name)都得覆盖你的DNS名称。我遇到过CN写对了但SAN没写,Chrome里能过,Safari里报错——浏览器实现不一样。
- 过期证书的预判:证书快过期时,你的监控应该能提前发现。别等到业务中断了才慌。我一般会给证书设置30天的提前预警。
openssl x509 -in your.crt -text -noout可以查看证书的完整信息。包括签发者、有效期、SAN列表等。调试时特别好用。
好了,关于CA、证书链和验证,大致就是这些内容。理解了这个模型,后面的TLS握手和加密通信,就更容易理清了。我的建议是:动手配一次。哪怕是自签一个链,亲自走一遍签发、部署、验证的流程,比看十遍文章都管用。