排查 HTTPS 连接故障时,第一步是确认两端实际协商的 TLS 版本。
openssl s_client:最通用的诊断工具
[1] openssl s_client 是 OpenSSL 自带的通用 TLS 客户端,适合直接探测远端服务端口。
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>&1 | grep -E 'Protocol|Cipher'
输出里的 Protocol : TLSv1.3 就是当前协商版本,Cipher 行会附带具体密码套件。
如果要测试服务端是否支持旧版本,可强制指定协议:
openssl s_client -connect example.com:443 -servername example.com -tls1_2 </dev/null 2>&1 | grep -E 'Protocol|Cipher|error'
OpenSSL 3.0(Ubuntu 22.04/24.04 自带)仍保留 -tls1_2、-tls1_3 等标志;[2] OpenSSL 1.1.1(Ubuntu 18.04/20.04)也支持同样的选项,行为一致。
注意:-servername 提供 SNI,现代 CDN 和云主机没有 SNI 往往直接返回默认站点或握手失败。
curl:无需额外安装
curl 在大多数发行版里已经预装,直接看 verbose 输出即可读取协商结果:[3]
curl -v https://example.com 2>&1 | grep -i 'SSL connection using'
典型输出:
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / id-ecPublicKey
这行同时给出协议版本、密码套件、密钥交换算法和证书签名算法。
gnutls-cli(可选)
如果系统装了 GnuTLS 工具链,[4] gnutls-cli 也能完成同样探测,且对 STARTTLS 场景更友好:
gnutls-cli example.com
连接建立后,终端会打印 - Protocol: TLSv1.3 这类信息。Ubuntu 下可通过 apt install gnutls-bin 获取。
排错速查表
| 现象 | 原因 | 处理 |
|---|---|---|
s_client 输出 handshake failure |
服务端禁用了客户端支持的协议版本 | 加 -tls1_2 或 -tls1_3 强制测试 |
s_client 没有 Protocol 行 |
缺少 SNI | 补上 -servername |
| curl 看不到 TLS 版本 | 被代理或证书校验中断 | 加 -k 仅看协议(不推荐生产环境) |
gnutls-cli 命令不存在 |
未安装 gnutls-bin | apt install gnutls-bin |
局限性
- WSL2 NAT 环境下部分外部主机会握手超时,属网络策略限制,非命令故障。
s_client默认不验证证书链;若需校验,加-verify 5。- OpenSSL 3.0+ 仍支持
-tls1/-tls1_1/-tls1_2/-tls1_3标志,但企业定制发行版可能在编译时屏蔽旧协议。 - 本文实测:Ubuntu 24.04 LTS,OpenSSL 3.0.13,curl 8.5.0;
gnutls-cli未安装。
FAQ
Q1: 本机怎么查看支持的 TLS 版本列表? 用 openssl ciphers -v 可看当前配置支持的密码套件,但不会列出协议版本。协议版本由编译时默认值和运行时配置共同决定。
Q2: s_client 和 curl -v 结果不一致怎么办? 先检查是否使用了相同的 SNI 和端口;s_client 默认不带 SNI,而 curl 会使用 URL 中的主机名作为 SNI。
Q3: 为什么 -tls1 在 OpenSSL 3 上报错? 部分发行版在 OpenSSL 3 配置文件中禁用了 TLS 1.0/1.1;可用 openssl list -tls-versions 查看实际启用的版本。
Q4: 能否批量检查多个域名? 可以写成循环脚本,但注意控制并发和超时,避免触发目标站点风控。
Q5: gnutls-cli 和 openssl s_client 哪个更准? 两者都调用系统信任库和协商逻辑,结果应当一致。差异通常来自默认密码套件优先级或 SNI 处理方式。
实测记录
测试机器:Ubuntu 24.04 LTS (Noble), WSL2, OpenSSL 3.0.13, curl 8.5.0。
$ openssl version
OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
$ openssl s_client -connect example.com:443 -servername example.com </dev/null 2>&1 | grep -E 'Protocol|Cipher'
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
$ openssl s_client -connect example.com:443 -servername example.com -tls1_2 </dev/null 2>&1 | grep -E 'Protocol|Cipher|error'
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Protocol : TLSv1.2
Cipher : ECDHE-ECDSA-CHACHA20-POLY1305
$ curl -v https://example.com 2>&1 | grep -i 'SSL connection using'
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / id-ecPublicKey
参考资料
- [1] openssl-s_client(1) — Ubuntu Noble(s_client-man)
- [2] openssl-s_client(1) — Ubuntu Bionic(s_client-old)
- [3] curl(1) — Ubuntu Noble(curl-man)
- [4] gnutls-cli(1) — Linux manual page(gnutls-man)
文中主要命令已在 WSL Ubuntu(24.04)实测,个别条目(未装工具/安装类命令)仅核对官方文档,未实际执行。