证书故障 90% 出在证书链和过期上
一句话总结
大多数证书故障与密码学无关,主要来自两件事:证书链缺少中间证书,以及无人关注的到期日。
为什么这是个问题
这两类问题之所以危险,是因为开发人员的电脑上往往无法复现。浏览器会缓存中间证书,或自动下载补全,所以即使服务器漏发证书链,页面也可能正常显示。但服务器之间的集成(Java 客户端、批处理)通常不做这种补偿,会直接失败。“我的浏览器明明可以”就是这样产生的。
到期问题更简单,也更严重。有效期一过,立刻就是全面故障,而且可能从凌晨开始。处理动作只是替换文件,但申请该文件却可能需要数日。所以这不是响应问题,而是监控问题:一个倒数剩余天数的脚本加一条告警就能解决,却每年都有系统因此故障。
SI 现场何时遇到证书
证书通常这样到手:客户安全团队通过邮件发送一个 .pfx 文件及密码,或发来 server.crt、server.key、chain.crt 三个文件,偶尔只给一个 .cer,并附一句“请在上线前配置”。
此时需要的不是密码学知识,而是确认每个文件包含什么的方法。
# 인증서 내용 보기 (주체, 발급자, 유효기간, SAN)
openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltName
# 키와 인증서가 짝인지 확인 (두 해시가 같아야 함)
openssl x509 -in server.crt -noout -modulus | openssl md5
openssl rsa -in server.key -noout -modulus | openssl md5
# pfx 를 crt/key 로 분해
openssl pkcs12 -in cert.pfx -clcerts -nokeys -out server.crt
openssl pkcs12 -in cert.pfx -nocerts -nodes -out server.key
密钥与证书不匹配时,nginx 甚至无法启动,只留下短短一条 key values mismatch。掌握上面两行命令,30 秒就能确认。
证书链——为什么开发电脑正常,服务器集成失败
证书通常有三层。
Root CA (브라우저·OS 에 이미 들어 있음)
└─ Intermediate CA (중간 인증서)
└─ 서버 인증서 (우리 것)
服务器必须同时发送自己的证书 + 中间证书,根证书则由对方预先持有。漏掉中间证书会发生什么?
- 浏览器:通常仍能工作,因为它可能缓存了从其他网站获得的中间证书,或通过 AIA 扩展自动下载。
- 服务器间通信(集成系统 HTTP 客户端、Java
HttpsURLConnection、curl):会失败。许多实现既没有缓存,也不会跟随 AIA。
因此会出现典型症状:“开发人员电脑的浏览器正常,只有对方集成系统报 SSL 错误。” 一行命令即可确认。
echo | openssl s_client -connect api.example.com:443 \
-servername api.example.com -showcerts 2>/dev/null | grep -c 'BEGIN CERTIFICATE'
输出 1 说明没有证书链。 正常应为 2 或更多。
nginx 的 ssl_certificate 应指向按服务器证书 → 中间证书顺序拼接的文件,顺序不能反。
cat server.crt intermediate.crt > fullchain.pem
没有 SAN,现代浏览器会拒绝
过去会把域名写在 CN(Common Name)中,如今若没有 **SAN(Subject Alternative Name)**扩展,现代浏览器会拒绝证书,CN 已退居参考用途。
自行签发证书时漏掉 SAN,反复追查“为什么不工作”的情况很常见。为开发/验证环境建立私有 CA 时必须加入 SAN。
subjectAltName = DNS:labhub.local, DNS:*.labhub.local, IP:127.0.0.1
到期——最常见也最荒唐的故障
真实案例中,一次大型 SSO 切换项目因 SAML 签名证书到期,造成 47 分钟全面登录故障。证书到期并非没有预告,因为日期从签发时就已确定;但负责人更换、告警邮件进入垃圾箱后,仍可能无人知晓。
所以,到期监控应由脚本而非人工完成。
openssl x509 -in server.crt -noout -enddate
# notAfter=Nov 12 09:00:00 2026 GMT
# 임계일 이내면 실패로 종료 (checkend 는 초 단위)
openssl x509 -in server.crt -noout -checkend $((30*86400)) \
|| echo "30일 이내 만료"
-checkend 很少被提及,却正适合构建监控脚本。不仅服务器证书,还要把集成对方证书、客户端证书、SAML 签名证书、代码签名证书统一列入清单。没有清单,必然会遗漏一个。
nginx TLS 配置的实务默认值
server {
listen 8443 ssl;
server_name labhub.local;
ssl_certificate /etc/nginx/tls/fullchain.pem;
ssl_certificate_key /etc/nginx/tls/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
ssl_protocols TLSv1.2 TLSv1.3——TLS 1.0/1.1 已被淘汰,也是韩国金融与公共领域安全检查的整改项。但现实中确有只支持 1.0 的老旧集成系统,此时应为对方另开专用端口并明确整改期限,不能降低整个系统。ssl_session_cache shared:SSL:10m——10MB 大约可保存四万个会话。会话复用能显著降低握手成本。ssl_prefer_server_ciphers off——当前建议在 TLS 1.3 中尊重客户端偏好。
HTTP → HTTPS 重定向
server {
listen 8088;
server_name labhub.local;
return 301 https://$host:8443$request_uri;
}
建议不使用 rewrite,而改用 return 301;后者更快,意图也更清晰。启用重定向后还应考虑 HSTS。不过,HSTS 一旦写入浏览器就很难撤回,内部系统应从较短的 max-age 开始,再逐步增加。