3. 证书颁发机构(CA):信任的起点与层级设计
说到CA,很多人第一反应就是「花钱买证书的地方」。其实不然。CA的核心角色,是建立信任的锚点。你想想看,互联网上两个素未谋面的实体,凭什么相信对方出示的证书是真的?就凭CA在中间做了担保。
我个人习惯把CA比作「数字世界的公证处」。公证处不能乱发公证书,CA也不能乱签证书。一旦CA的私钥泄露,或者签发流程有漏洞,整个信任链就崩塌了。我在项目中遇到过一家企业,内部CA的根证书私钥直接明文存在一台测试服务器上……嗯,那场面,简直是给攻击者送大礼。
3.1 CA的角色与信任模型
CA承担三个核心职责:
- 身份验证:确认申请证书的实体确实是它声称的那个实体
- 证书签发:用CA自己的私钥为申请者生成数字证书
- 生命周期管理:包括证书续期、吊销(CRL/OCSP)、归档
信任模型主要有三种:
| 信任模型 | 特点 | 典型场景 |
|---|---|---|
| 层次模型 | 根CA → 中间CA → 终端证书,单向信任链 | 公开CA(如DigiCert、Let's Encrypt) |
| 网状模型 | 多个CA互相交叉认证,双向信任 | 企业内部多部门互信 |
| 桥CA模型 | 一个桥CA连接多个独立的PKI域 | 跨组织、跨行业的联邦信任 |
实际生产环境中,层次模型用得最多。为什么?因为它好管理、好审计。根CA可以离线保存,中间CA负责日常签发,即使中间CA被攻破,根CA还在,可以吊销中间CA证书重新签发。我曾经帮一家金融客户做PKI改造,他们之前用的是单层CA——根CA直接签终端证书,结果根CA私钥必须在线,风险极高。改造成两层后,安全等级直接上了一个台阶。
核心原则:根CA必须离线,中间CA在线签发。这是PKI安全的第一条铁律。
3.2 自签名CA搭建实战
搭建一个自签名CA,说白了就是自己生成一对根密钥,然后自己给自己签一张根证书。下面我用OpenSSL演示,这是最通用的工具。
3.2.1 生成根CA私钥
# 生成RSA 4096位根CA私钥,加密存储
openssl genrsa -aes256 -out rootCA.key 4096
# 查看私钥信息
openssl rsa -in rootCA.key -text -noout
这里我建议用-aes256参数加密私钥。每次使用根CA私钥时都需要输入密码,虽然麻烦一点,但安全多了。我曾经见过有人图省事生成无密码的私钥,结果运维人员误操作把私钥文件传到了公网Git仓库……那真是灾难级的泄露。
3.2.2 生成根证书(自签名)
# 生成自签名根证书,有效期10年
openssl req -x509 -new -nodes -key rootCA.key \
-sha256 -days 3650 \
-out rootCA.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=MyRootCA"
注意几个关键点:
-x509:表示输出自签名证书,而不是证书签名请求-days 3650:根证书有效期通常设5-10年,太长有风险,太短管理成本高-subj:证书主题,CN(Common Name)要能唯一标识这个CA
小技巧:根证书的CN建议加上「Root CA」字样,方便后续区分。比如CN=MyCompany Root CA,一目了然。
3.2.3 生成中间CA
根CA搭好后,别急着用它签终端证书。先创建一个中间CA:
# 1. 生成中间CA私钥
openssl genrsa -aes256 -out intermediate.key 4096
# 2. 生成中间CA证书签名请求(CSR)
openssl req -new -key intermediate.key \
-out intermediate.csr \
-subj "/C=CN/ST=Beijing/O=MyCompany/CN=MyIntermediateCA"
# 3. 用根CA签发中间CA证书
openssl x509 -req -in intermediate.csr \
-CA rootCA.crt -CAkey rootCA.key \
-CAcreateserial -out intermediate.crt \
-days 1825 -sha256 \
-extensions v3_ca -extfile openssl.cnf
这里-extensions v3_ca是关键。它告诉OpenSSL:这张证书是一个CA证书,可以继续签发下级证书。如果不加这个扩展,中间CA签发的证书在客户端验证时会报错。
避坑指南:我曾经遇到一个案例,中间CA证书没有设置pathLenConstraint,结果下级又签了一个下级CA,导致信任链无限延伸。建议在v3_ca扩展中加上pathLenConstraint:0,限制中间CA只能签终端证书,不能再签下级CA。
3.3 根证书与中间证书的层级关系
层级关系,说白了就是一条信任链。客户端验证终端证书时,会沿着证书链一路向上找,直到找到本地信任的根证书。下面这张图展示了典型的二级CA结构:
层级设计的好处很明显:
- 安全隔离:根CA私钥可以放在离线机器甚至硬件加密机里,日常签发用中间CA
- 灵活吊销:中间CA泄露了,只需要吊销中间CA证书,根CA不受影响
- 策略分离:不同中间CA可以设置不同的证书策略,比如一个用于SSL,一个用于代码签名
实际部署时,我建议至少用两层。小型企业可以用两层(根CA + 中间CA),大型企业可以用三层(根CA + 策略CA + 签发CA)。层数越多,灵活性越高,但管理复杂度也成倍增加。我个人习惯是:能用两层解决的问题,绝不用三层。
经验之谈:根证书的有效期我一般设10年,中间CA设5年,终端证书设1-2年。这样既保证了根CA的稳定性,又通过终端证书的频繁轮换降低了单点风险。
3.4 证书链的验证机制
客户端验证证书链时,会做以下几件事:
- 从终端证书开始,读取
Issuer字段,找到签发它的CA证书 - 用CA证书的公钥验证终端证书的签名
- 重复步骤1-2,直到找到自签名的根证书
- 检查根证书是否在本地信任存储中
- 检查所有证书是否在有效期内、是否被吊销
这里有个容易踩的坑:证书链不完整。有些服务器只配置了终端证书,没有附带中间CA证书。客户端如果没有中间CA证书,就无法构建完整的信任链。我曾经排查过一个案例,某电商网站的证书在Chrome上正常,但在老旧Android浏览器上报错——就是因为旧浏览器没有缓存中间CA证书,而服务器又没有下发完整的证书链。
避坑指南:服务器配置证书时,一定要把终端证书和中间CA证书拼接在一起下发。Nginx配置中ssl_certificate指向的文件应该包含完整的证书链,顺序是:终端证书 → 中间CA证书 → 根证书(可选)。