SSL/TLS 证书故障排查实战指南

一、概述

SSL/TLS 证书是现代互联网服务的基石,证书故障会导致服务不可用、浏览器告警、API 调用失败等严重问题。本文档总结常见的 SSL/TLS 证书故障场景及排查方法。

二、常见故障现象

2.1 浏览器告警

  • ERR_CERT_DATE_INVALID - 证书过期或尚未生效
  • ERR_CERT_AUTHORITY_INVALID - 证书颁发机构不受信任
  • ERR_CERT_COMMON_NAME_INVALID - 域名不匹配
  • ERR_CERT_REVOKED - 证书已被吊销

2.2 命令行工具报错

1
2
3
4
5
6
# curl 报错
curl: (60) SSL certificate problem: certificate has expired
curl: (60) SSL certificate problem: unable to get local issuer certificate

# openssl 报错
openssl s_client: certificate verify error:num=20:unable to get local issuer certificate

2.3 应用层报错

1
2
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
Python requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

三、排查流程

3.1 第一步:检查证书基本信息

1
2
3
4
5
6
7
8
# 查看证书详细信息
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -text

# 快速查看证书有效期
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates

# 查看证书主题和颁发者
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer

关键检查点:

字段 说明
Not Before 证书生效时间,早于当前时间才有效
Not After 证书过期时间,晚于当前时间才有效
Subject CN 证书绑定的域名
Subject Alternative Name 证书支持的所有域名
Issuer 证书颁发机构

3.2 第二步:验证证书链完整性

1
2
3
4
5
# 查看完整证书链
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null

# 验证证书链(需要 CA 根证书)
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt server.crt

常见问题:

  1. 中间证书缺失 - 服务器只配置了叶子证书,缺少中间 CA 证书
  2. 证书链顺序错误 - 证书文件中的顺序应为:叶子证书 → 中间证书 → 根证书
  3. 自签名证书 - 内部服务使用自签名证书,客户端不信任

3.3 第三步:检查域名匹配

1
2
# 提取证书中的所有域名
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltName

匹配规则:

  • 精确匹配:www.example.com 匹配 www.example.com
  • 通配符匹配:*.example.com 匹配 api.example.com 但不匹配 example.com
  • 多域名证书:SAN 字段包含多个域名

3.4 第四步:检查证书吊销状态

1
2
3
4
5
# 获取 CRL 分发点
openssl x509 -in server.crt -noout -text | grep -A1 "CRL Distribution"

# 获取 OCSP 响应
openssl ocsp -issuer intermediate.crt -cert server.crt -url http://ocsp.example.com -resp_text

四、典型故障场景与解决方案

场景 1:证书过期

现象: 浏览器显示”您的连接不是私密连接”

排查:

1
openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -dates

解决方案:

  1. 立即联系证书颁发机构续期
  2. 临时方案:更新证书后重启服务
  3. 预防措施:设置证书过期监控告警(建议提前 30 天告警)

场景 2:证书链不完整

现象: 桌面浏览器正常,但移动端或某些客户端报错

排查:

1
2
# 检查服务器返回的证书数量
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null | grep -c "BEGIN CERTIFICATE"

解决方案:

  1. 获取完整的证书链文件(包含中间证书)
  2. Nginx 配置示例:
1
2
ssl_certificate /etc/nginx/ssl/fullchain.pem;  # 包含叶子 + 中间证书
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
  1. Apache 配置示例:
1
2
3
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateChainFile /etc/apache2/ssl/intermediate.crt
SSLCertificateKeyFile /etc/apache2/ssl/privkey.pem

场景 3:域名不匹配

现象: 访问 www.example.com 但证书只包含 example.com

排查:

1
openssl s_client -connect www.example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltName

解决方案:

  1. 申请包含所有域名的多域名证书(SAN 证书)
  2. 或使用通配符证书 *.example.com
  3. 确保访问域名与证书 SAN 列表匹配

场景 4:自签名证书不受信任

现象: 内部服务使用自签名证书,客户端报错

解决方案:

  1. 推荐方案:使用内部 CA 签发证书
  2. 临时方案:将自签名证书添加到客户端信任库
1
2
3
4
5
6
# Linux 系统添加信任
sudo cp internal-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

# Java 应用添加信任
keytool -importcert -file internal-ca.crt -keystore $JAVA_HOME/lib/security/cacerts -alias internal-ca

场景 5:TLS 版本或加密套件不兼容

现象: SSL_ERROR_NO_CYPHER_OVERLAP

排查:

1
2
3
4
5
6
# 检查服务器支持的 TLS 版本
nmap --script ssl-enum-ciphers -p 443 example.com

# 测试特定 TLS 版本
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

解决方案:

  1. 更新客户端支持更新的 TLS 版本
  2. 服务器端调整加密套件配置(在安全允许范围内)

五、监控与预防

5.1 证书过期监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# check_cert_expiry.sh

DOMAIN=$1
WARN_DAYS=30

EXPIRY=$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt $WARN_DAYS ]; then
echo "WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days"
exit 1
else
echo "OK: Certificate for $DOMAIN valid for $DAYS_LEFT days"
exit 0
fi

5.2 Prometheus 监控指标

1
2
3
4
5
6
7
# prometheus.yml 配置
scrape_configs:
- job_name: 'ssl_expiry'
static_configs:
- targets: ['example.com:443']
metrics_path: /probe
module: [ssl_cert]

5.3 自动化续期(Let’s Encrypt)

1
2
3
4
5
6
# 使用 certbot 自动续期
certbot renew --quiet --post-hook "systemctl reload nginx"

# 添加定时任务
crontab -e
# 0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"

六、常用工具汇总

工具 用途
openssl s_client 连接测试、证书查看
openssl x509 证书解析
curl -vI HTTP 请求测试
nmap ssl-enum-ciphers 加密套件扫描
sslscan SSL/TLS 安全扫描
testssl.sh 综合 SSL 安全测试
浏览器开发者工具 快速查看证书信息

七、故障排查清单

  • 证书是否在有效期内
  • 证书链是否完整
  • 域名是否匹配(CN 和 SAN)
  • 证书是否被吊销
  • TLS 版本是否兼容
  • 加密套件是否支持
  • 客户端是否信任 CA
  • 服务器配置是否正确

八、总结

SSL/TLS 证书故障排查的核心是:验证有效性 → 检查完整性 → 确认匹配性 → 排查兼容性。建议建立证书台账,实施自动化监控,避免证书过期导致的生产事故。