验证与连接测试
OpenSSL 密码套件与 TLS 版本:查看、测试与枚举
openssl ciphers 能查出某个套件字符串在你这版 OpenSSL 上代表哪些套件,openssl s_client 能测出服务器实际接受哪些协议版本、密码套件和密钥交换组。命令按 OpenSSL 3.x 写(输出取自 3.6.1),需要 3.4 或 3.5 的命令单独标注。名称背后的含义见密码套件原理,查单个套件可以用密码套件查询。
把套件字符串展开成具体套件
openssl ciphers -v 会列出 ECDHE+AESGCM 这类字符串选中的全部套件,以及各自的密钥交换、认证和加密算法。
openssl ciphers -v 'ECDHE+AESGCM'
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
前三个 TLS 1.3 套件总会出现,因为套件字符串管不到它们。语法上 + 表示同时满足,: 分隔多个条件,! 表示永久排除,@STRENGTH 表示按强度排序。TLS 1.2 那一列是该套件可用的最低版本,不代表只能用于 1.2。
只看某个协议版本会用到的套件
-s 只列出在当前设置下真正可用的套件,可以配合 -tls1_2 或 -tls1_3。
openssl ciphers -s -tls1_3 -v
openssl ciphers -s -tls1_2 | tr ':' '\n' | wc -l
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
27
TLS 1.3 一共定义了 5 个套件,OpenSSL 默认只启用 3 个,TLS_AES_128_CCM_SHA256 和 TLS_AES_128_CCM_8_SHA256 需要显式打开。第二条统计这版 OpenSSL 默认可用于 TLS 1.2 的套件数(27 个,另外还有 3 个 TLS 1.3 套件)。各 Linux 发行版经常改默认值,以你机器上的结果为准。
把 OpenSSL 名称换成 IANA 名称
-stdname 在 OpenSSL 名称旁边列出 RFC/IANA 标准名称,浏览器、Java、Go 用的都是后者。
openssl ciphers -stdname -s -tls1_2 'ECDHE+CHACHA20'
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 - ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
Nginx、Apache、HAProxy 的 ssl_ciphers 要写 OpenSSL 名称,Java、Go 的配置要写 IANA 名称。两种写法混用,是套件配置“写了不生效”的常见原因。
用 -ciphersuites 而不是 -cipher 指定 TLS 1.3 套件
TLS 1.3 套件由 -ciphersuites 控制,-cipher 对 TLS 1.3 握手不起作用。
openssl s_client -connect www.example.com:443 -tls1_3 -ciphersuites TLS_CHACHA20_POLY1305_SHA256 -brief < /dev/null
openssl s_client -connect www.example.com:443 -tls1_3 -cipher ECDHE-RSA-AES128-GCM-SHA256 -brief < /dev/null
Protocol version: TLSv1.3
Ciphersuite: TLS_CHACHA20_POLY1305_SHA256
...
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
第二次连接完全忽略了 -cipher,协商出的是默认套件。服务器配置也是这样分开的:Nginx 的 ssl_ciphers 只管 TLS 1.2 及以下,TLS 1.3 套件要用 ssl_conf_command Ciphersuites ...(Nginx 1.19.4 起支持)。绝大多数站点保持默认就好。
检查服务器接受哪些 TLS 版本
逐个版本发起握手,打印每次的结果。
for v in tls1_2 tls1_3; do
printf '%s: ' "$v"
openssl s_client -connect www.example.com:443 -servername www.example.com -"$v" -brief < /dev/null 2>&1 \
| grep -m1 -E 'Protocol version|alert|error' || echo failed
done
tls1_2: Protocol version: TLSv1.2
tls1_3: Protocol version: TLSv1.3
只支持 TLS 1.2 的服务器会对 -tls1_3 回 alert protocol version(告警 70)。截至 2026 年 11 月,公网站点完全关闭 TLS 1.2 仍然为时过早,部分老客户端和函数库还不支持 TLS 1.3。
确认 TLS 1.0 和 1.1 真的关掉了
OpenSSL 3.x 在安全级别 1 下连 TLS 1.0/1.1 都不会发起,所以下结论之前先加 @SECLEVEL=0。
openssl s_client -connect www.example.com:443 -tls1_1 < /dev/null
openssl s_client -connect www.example.com:443 -tls1_1 -cipher 'DEFAULT:@SECLEVEL=0' < /dev/null
...:error:0A0000BF:SSL routines:tls_setup_handshake:no protocols available:...
...:error:0A00042E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:...:SSL alert number 70
第一条错误来自你自己的客户端,跟服务器无关。第二条是服务器拒绝了 TLS 1.1,这才是想要的结果;如果第二条反而连上了,说明服务器仍允许 TLS 1.1。这一变化写在 OpenSSL 3.0 迁移指南里;RFC 8996 在 2021 年正式弃用了 TLS 1.0 和 1.1。等保测评、安全扫描报告里“支持不安全的 TLS 版本”这一项,就可以用这两条命令自查。
枚举服务器接受的全部套件
每次握手只尝试一个套件,把成功的记下来。
HOST=www.example.com; PORT=443
for c in $(openssl ciphers -tls1_2 'ALL:@SECLEVEL=0' | tr ':' ' '); do
echo | openssl s_client -connect $HOST:$PORT -servername $HOST -tls1_2 \
-cipher "$c:@SECLEVEL=0" >/dev/null 2>&1 && echo "TLSv1.2 $c"
done
for s in TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 \
TLS_AES_128_CCM_SHA256 TLS_AES_128_CCM_8_SHA256; do
echo | openssl s_client -connect $HOST:$PORT -servername $HOST -tls1_3 \
-ciphersuites $s >/dev/null 2>&1 && echo "TLSv1.3 $s"
done
TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384
TLSv1.2 ECDHE-ECDSA-CHACHA20-POLY1305
TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256
TLSv1.2 ECDHE-ECDSA-AES256-SHA384
TLSv1.2 ECDHE-ECDSA-AES128-SHA256
TLSv1.2 ECDHE-ECDSA-AES256-SHA
TLSv1.2 ECDHE-ECDSA-AES128-SHA
TLSv1.3 TLS_AES_128_GCM_SHA256
TLSv1.3 TLS_AES_256_GCM_SHA384
TLSv1.3 TLS_CHACHA20_POLY1305_SHA256
这台服务器用的是 OpenSSL 默认配置加 ECDSA 证书,TLS 1.2 下仍接受 4 个 CBC 套件。只有本机 OpenSSL 认识的套件才能被测到,被编译时去掉的套件永远不会出现。需要的话按同样方法加 -tls1、-tls1_1 的循环。ALL:@SECLEVEL=0 在 OpenSSL 3.6 上展开约 140 个套件,也就是要发起这么多次连接,请只对自己的服务器使用。
检查服务器是否同时部署了 ECDSA 和 RSA 证书
用 -sigalgs 限定签名算法,双证书服务器会返回对应类型的证书。
openssl s_client -connect www.example.com:443 -sigalgs 'ECDSA+SHA256' < /dev/null 2>/dev/null | grep -m1 'a:PKEY'
openssl s_client -connect www.example.com:443 -sigalgs 'RSA-PSS+SHA256:RSA+SHA256' < /dev/null 2>/dev/null | grep -m1 'a:PKEY'
a:PKEY: EC, (prime256v1); sigalg: ecdsa-with-SHA384
a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption
第二条如果报 alert handshake failure,说明服务器只有 ECDSA 证书,极少数很老的客户端会因此连不上。Nginx 部署双证书很简单:ssl_certificate 和 ssl_certificate_key 按密钥类型各写一组。
测试混合后量子密钥交换(OpenSSL 3.5+)
-groups X25519MLKEM768 只提供混合 ML-KEM 组,服务器支持才能握手成功。
openssl s_client -connect www.example.com:443 -groups X25519MLKEM768 -brief < /dev/null
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=www.example.com
Verification: OK
Negotiated TLS1.3 group: X25519MLKEM768
不支持 ML-KEM 的服务器会回 ssl/tls alert handshake failure ... SSL alert number 40。在默认设置下,OpenSSL 3.5+ 会同时发送 X25519MLKEM768 和 X25519 两个密钥份额,所以会悄悄回落,显示 Peer Temp Key: X25519, 253 bits。OpenSSL 3.0 到 3.4 根本不认识这个组名。背景见后量子 TLS 和 X25519MLKEM768。
查看提供的组和密钥份额大小
-trace 会解码 ClientHello 和 ServerHello,包括 supported_groups 和 key_share 扩展。
openssl s_client -connect www.example.com:443 -trace < /dev/null 2>&1 \
| grep -E 'supported_groups|key_share|NamedGroup|key_exchange: \(len' | cut -c1-70
extension_type=supported_groups(10), length=18
extension_type=key_share(51), length=1258
NamedGroup: X25519MLKEM768 (4588)
key_exchange: (len=1216): 00DDC3A82B7EB93BC261440DE87C418A717D3
NamedGroup: ecdh_x25519 (29)
key_exchange: (len=32): 233767194B5DECAE196362B3FC539DC6541371E
extension_type=key_share(51), length=1124
NamedGroup: X25519MLKEM768 (4588)
key_exchange: (len=1120): F4AB5DAE2E917CEBEA4E2B3BB80085B06DFE1
客户端的混合份额是 1216 字节(1184 字节 ML-KEM-768 封装公钥加 32 字节 X25519),服务器的是 1120 字节(1088 字节密文加 32 字节)。这个组的编号是 4588(0x11EC)。ClientHello 变大,正是部分老旧防火墙、中间设备处理后量子握手出问题的原因。
列出 KEM、签名算法和 TLS 组
openssl list 显示你这版 OpenSSL 及其 provider 支持哪些算法。
openssl list -kem-algorithms
openssl list -tls-groups # OpenSSL 3.5+
openssl list -tls-signature-algorithms # OpenSSL 3.4+
openssl list -signature-algorithms | grep -i -E 'ml-dsa|slh-dsa'
{ 2.16.840.1.101.3.4.4.2, id-alg-ml-kem-768, ML-KEM-768, MLKEM768 } @ default
X25519MLKEM768 @ default
SecP256r1MLKEM768 @ default
...
secp256r1:secp384r1:secp521r1:x25519:x448:...:MLKEM512:MLKEM768:MLKEM1024:SecP256r1MLKEM768:X25519MLKEM768:SecP384r1MLKEM1024
ML-KEM(FIPS 203)、ML-DSA(FIPS 204)和 SLH-DSA(FIPS 205)从 OpenSSL 3.5 起进入默认 provider,3.0 到 3.4 不加载外部 provider 就看不到它们。@ default 是实现该算法的 provider 名称。Ubuntu 22.04/24.04、Debian 12 等常见系统自带的仍是 3.0 系列,想测后量子要另装新版本。
提高或降低安全级别
套件字符串里的 @SECLEVEL=n 决定了可接受的密钥长度、签名算法和协议版本。
openssl s_client -connect www.example.com:443 -cipher 'DEFAULT:@SECLEVEL=2' -brief < /dev/null
openssl ciphers -s -tls1 -v 'DEFAULT:@SECLEVEL=0' | head -3
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
...
ECDHE-ECDSA-AES256-SHA TLSv1 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES256-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
级别 1(OpenSSL 默认)要求至少 80 位安全强度,禁止 SHA-1 和 MD5 签名;级别 2 要求 RSA、DSA、DH 密钥至少 2048 位,ECC 密钥至少 224 位。有些发行版把系统默认调到了级别 2,所以在这些系统上连接使用 1024 位 RSA 或 DH 参数的老服务器会报 dh key too small。级别 0 只在测试老旧系统时临时使用。
常见问题
openssl s_client -tls1_1 报 no protocols available 是什么意思?
这是本地客户端自己拒绝了。OpenSSL 3.x 在默认安全级别 1 下禁用 TLS 1.0/1.1,因为它们依赖 SHA-1/MD5 签名。加上 -cipher 'DEFAULT:@SECLEVEL=0' 再测;如果服务器随后回 alert protocol version(告警 70),才说明服务器确实关掉了 TLS 1.1。
TLS 1.3 里和 ECDHE-RSA-AES128-GCM-SHA256 对应的套件是哪个?
TLS 1.3 的套件名只包含 AEAD 加密算法和哈希,比如 TLS_AES_128_GCM_SHA256。密钥交换通过支持的组(X25519、X25519MLKEM768、P-256)单独协商,身份认证通过签名算法协商,所以套件名里不再出现 RSA 或 ECDSA。
不装扫描工具能枚举服务器支持的套件吗?
可以。上文的 bash 循环每次只用一个套件发起握手,打印成功的那些。速度比专门的扫描器慢,但只依赖 OpenSSL 本身,在宝塔面板的终端或云服务器上就能直接跑。