证书体系详解:X.509证书结构、CA与证书链、自签名证书与商业证书的选择

说到TLS,绕不开的就是证书。很多刚接触的人觉得证书就是个文件,装上就能用。其实不然。我在生产环境里见过太多因为证书理解不透彻导致的故障——有的是证书链没配全,有的是过期时间没算好,还有的是自签名证书在内部系统里埋了雷。

这一章,咱们就把证书体系彻底讲透。从X.509的结构,到CA和证书链的运作机制,再到自签名和商业证书的选型,我都会结合自己的踩坑经历来说。

X.509证书结构:一个证书里到底装了啥?

X.509是公钥证书的国际标准格式。说白了,它就是一个数字身份证。你打开一个证书文件,看到的那些字段,每一个都有它的用途。

一个标准的X.509 v3证书,包含以下核心字段:

字段 说明 我踩过的坑
版本号 目前主流是v3(值为2) 老系统只支持v1,升级时要注意
序列号 CA颁发的唯一编号 吊销时靠它定位,别弄丢了
签名算法 如SHA256-RSA SHA1已被弃用,别再用
颁发者 签发该证书的CA名称 链校验时逐级匹配这个字段
有效期 notBefore 和 notAfter 时区问题导致证书提前过期,我吃过亏
主体 证书持有者的DN CN字段在浏览器里已不再被信任
公钥 RSA/ECC公钥及算法参数 密钥长度不够,会被安全扫描报高危
扩展 SAN、Key Usage、CA标志等 SAN没配全,浏览器报不安全

重点:SAN(Subject Alternative Name)

从Chrome 58开始,浏览器只看SAN,不再看CN。我遇到过同事配了CN没配SAN,结果内网系统全部报证书错误。记住:SAN才是现代TLS的域名绑定方式。

用OpenSSL查看证书内容的命令很简单:

openssl x509 -in certificate.crt -text -noout

你会看到一长串输出。别被吓到,核心就是上面那张表里的内容。我个人习惯先看Subject和Issuer,再看X509v3 extensions里的SAN和CA标志。

CA与证书链:信任是怎么传递的?

CA(Certificate Authority)就是证书颁发机构。它的作用很简单:担保一个公钥确实属于某个实体。

但这里有个关键问题——CA自己也需要被信任。这就引出了证书链的概念。

证书链的层级

典型的证书链有三层:根CA → 中间CA → 服务器证书。根CA自签名,中间CA由根CA签发,服务器证书由中间CA签发。浏览器只预置了根CA的证书,中间CA和服务器证书需要在TLS握手时一起下发。

我曾经遇到一个案例:某电商平台的Android客户端连不上生产环境,iOS却正常。查了半天,发现是Nginx只配了服务器证书,没配中间证书。Android对证书链的校验比iOS严格,直接拒绝了连接。

证书链的校验流程是这样的:

  1. 客户端收到服务器证书,提取颁发者信息
  2. 在已信任的CA列表中查找匹配的颁发者证书
  3. 用颁发者的公钥验证服务器证书的签名
  4. 如果颁发者不是根CA,继续向上查找,直到根CA
  5. 验证根CA是否在客户端的信任存储中

下面这张图展示了完整的证书链结构:

X.509证书链结构图 根CA证书 自签名 · 信任锚点 中间CA证书 由根CA签发 服务器证书(叶子证书) 由中间CA签发 · 包含SAN TLS握手时,服务器必须下发完整证书链:服务器证书 + 中间CA证书 根CA证书由客户端信任存储提供,不需要下发

常见错误:证书链不完整

很多人在Nginx或Apache里只配置了服务器证书,没配中间证书。结果就是:部分客户端(尤其是移动端)无法建立TLS连接。我曾经在升级内部CA时漏掉了中间证书,导致全公司OA系统瘫痪了半小时。

正确的做法是:把服务器证书和中间CA证书合并成一个文件,或者分别在配置中指定。Nginx示例:

ssl_certificate /etc/nginx/ssl/example.com.fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

其中fullchain.pem包含服务器证书和中间CA证书。

自签名证书 vs 商业证书:怎么选?

这是个老生常谈的问题,但很多人选错了。我见过不少团队在内部生产环境用自签名证书,结果出了问题排查半天。

先看对比:

维度 自签名证书 商业证书
成本 免费 每年几百到几千元
信任 需要手动导入到每台设备 浏览器/系统默认信任
有效期 自己定,最长可到10年 通常1年,最长2年
吊销能力 需要自建CRL/OCSP CA提供吊销服务
审计合规 通常不满足 满足大部分合规要求

我的建议很明确:

  • 开发/测试环境:用自签名证书,省事省钱。但记得把根CA证书加到团队的信任存储里。
  • 内部生产环境:如果团队规模小、设备可控,可以用自建CA签发证书。但要做好证书生命周期管理。
  • 面向公网的服务:必须用商业证书。别犹豫,这是底线。

自签名证书的正确用法

如果你决定用自签名证书,别直接生成一个服务器证书就完事。正确的做法是:

  1. 先生成一个自签名的根CA证书
  2. 用根CA签发中间CA证书
  3. 用中间CA签发服务器证书

这样,你只需要把根CA证书导入到客户端,后续所有由该CA签发的证书都会被信任。我在公司内部就是这样做的,管理了上百个内部服务。

生成自签名根CA和服务器证书的步骤:

# 1. 生成根CA私钥和证书
openssl genrsa -out root-ca.key 4096
openssl req -x509 -new -nodes -key root-ca.key \
  -sha256 -days 3650 -out root-ca.crt \
  -subj "/C=CN/O=MyCompany/CN=MyRootCA"

# 2. 生成服务器证书私钥和CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
  -subj "/C=CN/O=MyCompany/CN=example.com"

# 3. 用根CA签发服务器证书
openssl x509 -req -in server.csr \
  -CA root-ca.crt -CAkey root-ca.key \
  -CAcreateserial -out server.crt -days 365 \
  -sha256 -extfile <(echo "subjectAltName=DNS:example.com,DNS:*.example.com")

自签名证书的坑

我曾经在内部日志系统上用了自签名证书,有效期设了10年。结果第三年的时候,根CA私钥泄露了。所有由该CA签发的证书都得重新生成,还要逐个更新客户端的信任存储。那叫一个痛苦。

所以,如果你用自签名证书,一定要做好私钥保护,并且定期轮换。别以为内网就安全。

商业证书的选择上,我个人偏好Let's Encrypt。免费、自动化、信任度高。配合acme.sh或Certbot,证书续期完全自动化。对于公网服务,这是目前最省心的方案。

但要注意,Let's Encrypt证书有效期只有90天。自动化续期脚本必须稳定可靠。我见过因为DNS解析问题导致续期失败,证书过期服务中断的案例。

总结一下:

  • X.509证书的核心字段要理解,尤其是SAN和CA标志
  • 证书链必须完整,中间证书不能漏
  • 自签名证书适合内部可控环境,商业证书是公网服务的标配
  • 无论哪种证书,生命周期管理都要重视

证书体系是TLS的基石。这块搞明白了,后面的部署和排错就会顺畅很多。