首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >用 openssl 排查 HTTPS 证书问题:过期、证书链不完整与 SNI 不匹配

用 openssl 排查 HTTPS 证书问题:过期、证书链不完整与 SNI 不匹配

原创
作者头像
一只特立独行的兔先生
发布于 2026-10-31 21:28:36
发布于 2026-10-31 21:28:36
1100
举报

背景

网站接入 HTTPS 后,常见的故障有三类:证书过期、浏览器提示“不受信任”、个别客户端(尤其是 Java、Android 旧版本、curl)握手失败而浏览器正常。这些问题用 openssl 和 curl 就能快速定位,不需要先猜。

一、查看证书的有效期、域名与签发者

代码语言:bash
复制
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

输出重点:

  • notAfter:证书到期时间,确认是否已过期或临近过期。
  • subjectAltName:证书覆盖的域名列表。现代客户端以 SAN 为准,不再只看 CN。
  • issuer:签发机构,用于判断链是否对得上。

-ext 选项需要 OpenSSL 1.1.1 及以上版本,低版本可用 -text 查看全部内容。

二、检查证书链是否完整

浏览器“不受信任”最常见的原因是服务器只配置了域名证书,缺少中间证书。部分浏览器会自动补全中间证书所以表面正常,但 curl、Java 等不会,从而表现为“浏览器能开,程序报错”。

代码语言:bash
复制
echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null

关注两处:

  1. 输出开头的 Certificate chain 部分,正常应当看到域名证书和至少一级中间证书。
  2. 末尾的 Verify return code:0 (ok) 表示验证通过;21 (unable to verify the first certificate) 或 20 通常说明缺少中间证书。

修复方式是在服务端配置包含完整链的证书文件,即域名证书在前、中间证书在后。以 Nginx 为例:

代码语言:nginx
复制
server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate     /etc/nginx/ssl/example.com_bundle.crt;  # 域名证书 + 中间证书
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
}

证书服务商下载包里通常提供合并好的 bundle 文件,以及单独的证书文件,使用 bundle 文件即可。根证书无需放入链中,客户端自带信任库。

三、SNI 不匹配:拿到的不是预期的证书

同一个 IP 上托管多个 HTTPS 域名时,服务器依赖客户端在握手中发送的 SNI 来选择证书。如果不带 -servername,openssl s_client 不会发送 SNI,服务器会返回默认证书,容易误判。

代码语言:bash
复制
# 不带 SNI,可能得到默认证书
echo | openssl s_client -connect 1.2.3.4:443 2>/dev/null | openssl x509 -noout -subject

# 带 SNI,模拟浏览器访问指定域名
echo | openssl s_client -connect 1.2.3.4:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject

对比两次输出,可以确认服务端的虚拟主机与证书是否对应。用 CDN、负载均衡或网关做回源时,回源请求是否带正确的 SNI 也是常见问题来源。

四、用 curl 验证真实请求

代码语言:bash
复制
curl -vI https://example.com 2>&1 | grep -E 'SSL|subject|issuer|expire|HTTP/'

# 指定解析到某个 IP,绕过 DNS 测试某台后端
curl -vI --resolve example.com:443:1.2.3.4 https://example.com

--resolve 能让你在不改 hosts 的前提下,让请求带着正确的域名和 SNI 发往指定 IP,适合逐台检查多个节点是否部署了同样的证书。

五、证书和私钥是否匹配

更换证书后服务无法启动,常见原因是证书与私钥不是一对。对比公钥摘要:

代码语言:bash
复制
openssl x509 -noout -pubkey -in example.com.crt | openssl sha256
openssl pkey -pubout -in example.com.key | openssl sha256

两个摘要一致才是同一对。

六、过期提醒

可以用脚本检查剩余天数,配合定时任务和告警:

代码语言:bash
复制
end=$(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)
days=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
echo "剩余 ${days} 天"

告警阈值按证书续期流程的耗时来定,留出足够的处理时间。使用自动续期时,也要监控续期任务是否真的成功,并在续期后重载服务。

排查顺序

  1. 带 -servername 查看证书的 SAN 和有效期。
  2. 看 Verify return code 与证书链是否完整。
  3. 不带和带 SNI 各查一次,确认虚拟主机配置。
  4. 用 curl --resolve 逐台验证后端节点。
  5. 更换证书后核对证书与私钥是否匹配。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 背景
  • 一、查看证书的有效期、域名与签发者
  • 二、检查证书链是否完整
  • 三、SNI 不匹配:拿到的不是预期的证书
  • 四、用 curl 验证真实请求
  • 五、证书和私钥是否匹配
  • 六、过期提醒
  • 排查顺序
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档