HTTPS 连接失败时,浏览器往往只给出一个模糊的错误码,而服务器日志也可能不够详细。此时,OpenSSL 命令行工具中的 s_client 和 s_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 failure 或 certificate 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 initialization、SSL_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 code 为 20 (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_client 和 s_server 是 HTTPS 诊断中不可替代的工具。s_client 让你从客户端角度看到证书链、协议版本和加密套件的真实情况;s_server 则帮你模拟服务端,验证客户端行为和证书配置。掌握它们,你就能在浏览器报错之前,先一步定位问题的根源。下次遇到 HTTPS 连接异常时,不妨先打开终端,用这两把利器探一探究竟。
未经允许不得转载:任鹏个人博客 » 用 OpenSSL 命令行诊断 HTTPS 连接问题:s_client 与 s_server 实战


朋友圈点赞图在线生成源码