DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

OpenSSL s_client 指定了 -servername,证书名称不匹配却仍连接成功

OpenSSL s_client 的 -servername 负责发送 SNI,不能代替证书名称验证。结合 -verify_hostname 与 -verify_return_error 区分选择站点、校验身份和遇错继续的行为。

用 openssl s_client 连接 TLS 服务,已经指定 -servername,服务器证书却不覆盖预期域名,连接仍然建立,甚至显示 Verify return code: 0 (ok)。首先检查是否明确启用了证书名称验证;发送 SNI 本身不完成这项检查。

下文针对 OpenSSL 3.x 的普通证书验证,不涉及 DANE。名为 openssl 的程序也可能来自其他实现,先通过 openssl version 核对,不要把旧版或 LibreSSL 的选项直接视为相同。

三个参数回答三个不同的问题

-connect 决定连接的地址与端口。-servername 把指定名称放进 ClientHello 的 SNI 扩展,帮助服务器选择站点和证书。-verify_hostname 则指定客户端期望证书覆盖的 DNS 名称。

服务器可以忽略不认识的 SNI、返回默认站点证书,也可以直接拒绝握手。客户端不能把“服务器愿意继续握手”当作服务身份已经匹配的证明。

对于普通 s_client 检查,没有指定预期名称时,证书链验证成功并不证明证书覆盖了你想访问的域名。另一个容易混淆的参数是 -verify 2:它设置验证深度并开启证书验证,不是让客户端核对名为 2 的主机,更不能代替 -verify_hostname。

同时指定名称检查和失败处理

下面在读者自己的测试终端中检查一个已授权的 TLS 端点。IP、域名与 CA 文件均为占位值,必须替换。trusted-ca.pem 应来自已经确认的系统或组织信任配置,不是随手从待检查服务器下载的证书。

openssl s_client -brief \
  -connect 192.0.2.20:443 \
  -servername app.example.com \
  -verify_hostname app.example.com \
  -verify_return_error \
  -CAfile ./trusted-ca.pem

这条命令可以连接固定 IP,同时验证证书是否适用于 app.example.com。连接地址写 IP,并不意味着应把名称检查也改成这个 IP;应按应用实际要认证的服务身份决定。

-verify_return_error 使证书验证错误中止握手。s_client 是诊断工具,默认可以打印验证错误后继续连接,方便观察更多信息;只加名称检查但仍允许错误继续,就可能再次把“连接没断”误当成功。

命令用于交互诊断。看到完整握手与验证结果后,可在行首输入 Q 并回车结束会话。不要为了让脚本立刻结束便假定标准输入 EOF 后一定已经取得全部结果;非交互使用在某些情形,尤其 TLS 1.3 下可能提前关闭。自动检查还需要设计期限、协议结束方式和退出状态处理,不能只搜索日志里的一个 ok。

验证目标名称不能从错误证书反向选择

如果实际访问的服务名是 app.example.com,就应验证这个名字。发现证书写着别的域名后,把 -verify_hostname 改成那个名字,只是换了要认证的身份,并没有修好原目标。

检查失败时区分错误:名称不匹配要核对目标域名、虚拟主机选择和证书覆盖范围;不受信任或链不完整要检查信任配置与服务端链;过期则检查证书有效期及系统时间。不要用删除 -verify_return_error 来让结果看起来正常。

如果应用确实以 IP 地址作为服务身份,应使用 -verify_ip 检查证书中的 IP 地址 SAN。它与 DNS 名称检查不同,不能把 DNS SAN 里看起来像 IP 的文字当成相同类型。也不要仅凭 Subject 中的一段 CN 文本就认定名称匹配,证书可能包含多个 SAN,实际匹配由验证规则决定。

用正确名称和错误名称做受控对照

在测试端点保持 -connect、SNI 和信任文件相同,只把 -verify_hostname 换成一个确定不被证书覆盖的测试名称。这样可以避免服务器因为 SNI 变化选了另一张证书,干扰判断。

预期是正确名称能够通过相应验证,错误名称触发名称不匹配并中止握手。若两次都在获取证书前失败,先处理连接或协议问题;若两次都因信任链失败,也还不能据此判断名称检查结果。

这项调整只修正诊断命令的验证要求,不修改服务器。保留原检查脚本以便比对;若新检查暴露既有证书问题,应修证书或服务配置,而不是恢复忽略名称的检查后宣布恢复正常。TLS 验证通过也不等于 HTTP 路由、登录或其他业务功能已经验收。