3. 证书体系:X.509证书结构、CA信任链、证书颁发、自签名证书
证书体系,说白了就是互联网世界的身份证系统。你想想看,浏览器和服务器之间要建立加密连接,总得先证明“我是我自己”吧?这就是证书干的事。我在早期做负载均衡项目时,曾因为搞混了证书链的根证书和中间证书,导致线上业务大面积断连……嗯,从那以后我对证书结构就格外上心了。
3.1 X.509证书结构:拆开看里面的东西
X.509是国际标准,定义了证书长什么样。平时我们看到的 .crt、.pem 文件,里面其实是一堆字段。我最常被问到的问题是:“为什么证书里会有公钥?”这其实很好理解——证书就是个信封,外面包着身份信息,里面装着公钥。
| 字段 | 说明 | 我的项目经验 |
|---|---|---|
| 版本号 (Version) | 一般为 V3,支持扩展字段 | V1 和 V2 基本绝迹,不用理会 |
| 序列号 (Serial Number) | CA 分配给证书的唯一编号 | 吊销证书时靠它来找 |
| 签名算法 (Signature Algorithm) | 如 SHA256WithRSA | 别用 SHA1,不安全 |
| 颁发者 (Issuer) | 签发此证书的 CA 名称 | 根证书的颁发者是自己 |
| 有效期 (Validity) | 开始和结束时间 | 快过期前一定要续期 |
| 主体 (Subject) | 证书持有者的名称 | 通常是域名或公司名 |
| 公钥 (Public Key) | 非对称加密的公钥部分 | 离线负载均衡器需要导入这个 |
| 扩展 (Extensions) | 如 SAN、密钥用法等 | SAN 填错会导致浏览器报不安全 |
看一个证书的实际内容,用 OpenSSL 命令就行:
openssl x509 -in example.crt -text -noout
你会看到输出结果里有一大段。其中 Subject Alternative Name (SAN) 是我最常检查的字段。因为 Chrome 从 Chrome 58 开始,只认 SAN,不认 Common Name(CN)了。我见过不少同事在 SAN 里只写了一个域名,结果用户通过 IP 访问时证书报错……
3.2 CA信任链:为什么你的浏览器信任这张证书?
这是个好问题。你的浏览器凭什么相信一个陌生网站发来的证书?答案在“信任链”上。
想象一下:你有个朋友 A,他介绍了朋友 B 给你认识,说 B 值得信任。你信任 A,所以也信任了 B。CA 证书链就是这逻辑——你的操作系统或浏览器里内置了一批“根证书”,它们就是那个 A。根证书签发了中间 CA,中间 CA 再签发给网站。一层层下来,只要根证书不被篡改,整条链就合法。
信任链的核心原则:
- 每个证书的颁发者,就是上一级证书的主体
- 根证书是自签名的:它的颁发者等于主体
- 服务器必须把整条链发给客户端(除了根证书)
我之前在负载均衡器上部署证书时,只上传了服务器证书,没带中间 CA 证书。结果呢?浏览器找不到完整的信任链,直接弹出了“不安全”的警告。用户电话被打爆了……所以记住,部署 SSL Offloading 时,一定要把服务器证书和中间证书拼成一个文件上传。
3.3 证书颁发:从 CSR 到签发
申请证书,其实就是走一套固定的流程。我每年都要走好几遍,已经完全肌肉记忆了。
- 生成密钥对:私钥自己保留,公钥放进证书请求文件(CSR)
- 生成 CSR:里面包含你的域名、组织信息、公钥
- 提交给 CA:CA 会验证你的域名所有权
- CA 签发:CA 用它的私钥给 CSR 里的公钥签名
- 拿到证书文件:一般都是 PEM 格式
小技巧:生成 CSR 时,Common Name 直接填主域名就行。SAN 里多填几个备用域名和 IP。我曾经只填了 www.example.com,结果 API 子域名的调用全挂了……
生成 CSR 的命令:
openssl req -new -newkey rsa:2048 -nodes -keyout myserver.key -out myserver.csr
执行后会问你一堆问题。Country Name 填 CN,Organization Name 填公司名,Common Name 填你的域名。其他字段可以留空。
3.4 自签名证书:自己当CA
内部测试、开发环境、POC 项目,你真的需要花钱买证书吗?完全不需要。自己签一个就行。
自签名证书,就是你自己创建根 CA,然后签发自用证书。整个过程都在你的机器上完成,不经过任何外部 CA。
注意:自签名证书不会被浏览器默认信任。部署到生产环境时,一定要换成由公共 CA 签发的证书。我曾经在内部系统里忘了换,结果第三方集成时直接被拒……
生成自签名证书的步骤:
- 创建根 CA 的私钥和自签名证书
- 为服务器生成私钥和 CSR
- 用根 CA 的私钥签发服务器证书
你实际只需要两条命令就够了:
# 一步生成自签名证书(适合快速测试)
openssl req -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 365
# 查看刚生成的证书
openssl x509 -in server.crt -text -noout
这个方法生成的证书,浏览器会提示“不安全”。你需要在浏览器里手动导入 server.crt 为受信任的根证书,才能消除警告。我在做负载均衡测试时,经常用这种方式快速验证配置是否正确。
自签名 vs 公共CA 证书对比:
| 维度 | 自签名 | 公共CA |
|---|---|---|
| 成本 | 0 | 几百到几千元/年 |
| 浏览器信任 | 不信任 | 默认信任 |
| 适用场景 | 开发、测试、内网 | 生产、公网 |
| 有效期 | 自己定,最长10年都行 | 最长397天(新规) |
| 吊销 | 靠CRL手动管理 | CA自动维护 |
最后说一个我踩过的坑。有一次我生成自签名证书时,忘了加 SAN 扩展字段。结果 Chrome 死活不认,报了个“NET::ERR_CERT_COMMON_NAME_INVALID”。我当时排查了半小时,才意识到是 SAN 的问题。所以现在我的习惯是,生成证书时一定要加上:
-addext "subjectAltName = DNS:localhost,DNS:*.example.com,IP:127.0.0.1"
有了这个扩展,自签名证书在开发环境里就畅通无阻了。