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 时,一定要把服务器证书和中间证书拼成一个文件上传。

X.509 证书信任链结构 根证书 (Root CA) 自签名,浏览器内置 中间CA证书 由根CA签发 服务器证书 由中间CA签发 客户端 (浏览器/APP) CA 是信任锚点 所有风险集中在这里 缺失中间证书记 导致链断裂

3.3 证书颁发:从 CSR 到签发

申请证书,其实就是走一套固定的流程。我每年都要走好几遍,已经完全肌肉记忆了。

  1. 生成密钥对:私钥自己保留,公钥放进证书请求文件(CSR)
  2. 生成 CSR:里面包含你的域名、组织信息、公钥
  3. 提交给 CA:CA 会验证你的域名所有权
  4. CA 签发:CA 用它的私钥给 CSR 里的公钥签名
  5. 拿到证书文件:一般都是 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 签发的证书。我曾经在内部系统里忘了换,结果第三方集成时直接被拒……

生成自签名证书的步骤:

  1. 创建根 CA 的私钥和自签名证书
  2. 为服务器生成私钥和 CSR
  3. 用根 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"

有了这个扩展,自签名证书在开发环境里就畅通无阻了。