用 OpenSSL 命令行诊断 HTTPS 连接问题:s_client 与 s_server 实战

HTTPS 连接失败时,浏览器往往只给出一个模糊的错误码,而服务器日志也可能不够详细。此时,OpenSSL 命令行工具中的 s_clients_server 就成了最直接、最可靠的诊断利器。它们能让你深入 TLS 握手过程,看到证书、协议版本、加密套件等每一个细节。本文将通过实战场景,带你掌握这两个工具的核心用法。

为什么选择 OpenSSL 命令行

浏览器和图形化工具隐藏了太多底层信息。当你遇到以下问题时,命令行往往能更快定位:

  • 证书链不完整,浏览器提示 NET::ERR_CERT_AUTHORITY_INVALID
  • 服务器只支持过时的 TLS 版本,导致现代客户端拒绝连接
  • SNI(服务器名称指示)配置错误,返回了错误的证书
  • 客户端证书认证失败,但错误信息不明确

OpenSSL 的 s_client 模拟一个 TLS 客户端,s_server 模拟一个 TLS 服务端。两者配合,可以覆盖从客户端到服务端的完整诊断链路。

s_client:从客户端视角诊断

基础连接与证书查看

最简单的用法是直接连接目标主机的 443 端口:

openssl s_client -connect example.com:443 -servername example.com

-servername 用于指定 SNI,现代服务器通常依赖它来返回正确的证书。如果不加这个参数,你可能会看到默认虚拟主机的证书,从而误判问题。

连接成功后,输出会包含完整的证书链、协议版本、加密套件等信息。关键部分包括:

  • Certificate chain:显示服务器发送的所有证书。如果只有叶子证书而没有中间 CA,说明链不完整。
  • SSL-Session 部分:Protocol 显示协商的 TLS 版本,Cipher 显示加密套件。
  • Verify return code:如果非 0,说明证书验证失败,后面会跟具体原因。

验证证书链完整性

要专门检查证书链,可以加上 -showcerts 参数:

openssl s_client -connect example.com:443 -servername example.com -showcerts

输出会以 PEM 格式打印每张证书。你可以将中间证书保存下来,与服务器配置进行比对。如果服务器只发送了叶子证书,你需要手动补全中间证书。

检查协议与加密套件支持

有时你需要确认服务器是否支持某个特定的 TLS 版本。使用 -tls1_2-tls1_3 强制指定:

openssl s_client -connect example.com:443 -servername example.com -tls1_2

如果握手失败,输出会明确提示 no protocols available 或类似错误。类似地,可以用 -cipher 指定加密套件:

openssl s_client -connect example.com:443 -servername example.com -cipher 'ECDHE-RSA-AES128-GCM-SHA256'

这在排查老旧客户端兼容性问题时非常有用。

客户端证书认证

如果服务器要求客户端证书,使用 -cert-key 参数:

openssl s_client -connect example.com:443 -servername example.com -cert client.crt -key client.key

握手成功后,输出中会显示 Client Certificate Types 和实际发送的证书。如果服务器拒绝,你会看到 alert handshake failurecertificate required 等提示。

模拟特定 SNI 或 Host 头

有时问题出在 SNI 与 HTTP Host 头不一致。s_client 只负责 TLS 层,但你可以手动发送 HTTP 请求来验证:

openssl s_client -connect example.com:443 -servername example.com -quiet
GET / HTTP/1.1
Host: example.com

-quiet 会抑制部分输出,让你直接看到 HTTP 响应。如果返回 404 或 421,说明服务器配置可能有问题。

s_server:从服务端视角验证

s_server 用于搭建一个临时的 TLS 服务端,常用于测试客户端行为或验证证书配置。

启动一个简单的 HTTPS 服务

openssl s_server -accept 8443 -cert server.crt -key server.key -www

-www 会启动一个简单的 HTTP 响应页面,返回连接信息。你可以用浏览器或 s_client 连接 localhost:8443 来测试。

验证客户端证书

要测试客户端证书认证,加上 -Verify 参数:

openssl s_server -accept 8443 -cert server.crt -key server.key -Verify 1 -CAfile ca.crt

-Verify 1 表示要求客户端证书并验证。如果客户端未提供或验证失败,握手会终止。你可以用 s_client 配合 -cert 来模拟客户端,观察双方交互。

调试 TLS 握手细节

s_server-state-debug 参数可以打印详细的握手状态:

openssl s_server -accept 8443 -cert server.crt -key server.key -state -debug

输出会显示每一步的状态转换,例如 SSL_accept:before SSL initializationSSL_accept:SSLv3/TLS read client hello 等。当握手在某个阶段卡住时,这些信息能帮你快速定位是客户端还是服务端的问题。

实战案例:诊断证书链不完整

假设浏览器访问 https://example.com 报错 NET::ERR_CERT_AUTHORITY_INVALID,但服务器配置看起来正常。用 s_client 检查:

openssl s_client -connect example.com:443 -servername example.com -showcerts

输出中 Certificate chain 只显示了一张证书,且 Verify return code20 (unable to get local issuer certificate)。这说明服务器没有发送中间 CA 证书。

解决方案:将中间 CA 证书追加到服务器证书文件中。例如在 Nginx 中:

ssl_certificate /path/to/fullchain.crt;  # 包含叶子证书和中间证书
ssl_certificate_key /path/to/private.key;

修复后再次用 s_client 验证,Verify return code 应变为 0 (ok),且 Certificate chain 会显示多张证书。

常用参数速查

s_client 常用参数:

  • -connect host:port:指定目标
  • -servername name:设置 SNI
  • -showcerts:打印完整证书链
  • -tls1_2 / -tls1_3:强制协议版本
  • -cipher:指定加密套件
  • -cert / -key:客户端证书
  • -quiet:减少输出
  • -verify_return_error:验证失败时立即退出

s_server 常用参数:

  • -accept port:监听端口
  • -cert / -key:服务端证书
  • -www:启用简单 HTTP 响应
  • -Verify:要求客户端证书
  • -CAfile:信任的 CA 证书
  • -state / -debug:打印握手细节

总结

OpenSSL 的 s_clients_server 是 HTTPS 诊断中不可替代的工具。s_client 让你从客户端角度看到证书链、协议版本和加密套件的真实情况;s_server 则帮你模拟服务端,验证客户端行为和证书配置。掌握它们,你就能在浏览器报错之前,先一步定位问题的根源。下次遇到 HTTPS 连接异常时,不妨先打开终端,用这两把利器探一探究竟。

未经允许不得转载:任鹏个人博客 » 用 OpenSSL 命令行诊断 HTTPS 连接问题:s_client 与 s_server 实战

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏