该错误发生在 TLS 协议的初始协商阶段,属于 fatal alert(级别 2),服务端或客户端在收到对方 Hello 消息后无法继续协商,直接发送 alert 并关闭连接。常见于 TLS 1.2 升级 TLS 1.3 过渡期、老旧客户端访问现代服务端、或证书签名算法不兼容等场景。它不是证书过期或域名不匹配类错误,不触发浏览器证书警告页,而是直接表现为连接重置或空响应。TLS 握手失败必须通过协议层日志定位,而非仅依赖应用层错误信息。
首先确认是否为服务端主动拒绝:使用 openssl s_client -connect example.com:443 -tls1_2 -cipher 'DEFAULT@SECLEVEL=1' 分别测试 TLS 1.2 / TLS 1.3 及不同 cipher suite 子集;若所有组合均返回 SSL routines::handshake failure,且服务端日志显示 no ciphers available 或 no shared signature algorithms,则判定为协商能力缺失。
signature_algorithms_cert 扩展,导致证书链中 ECDSA 证书与客户端支持的签名算法无交集; - 使用国密 SSL证书 时,服务端启用了 SM2/SM3/SM4 套件,但客户端未启用国密 TLS 扩展(需专用 SDK 或国密浏览器)。第一步:捕获完整握手报文。使用 Wireshark 过滤 tls.handshake.type == 1 or tls.handshake.type == 2 or tls.handshake.type == 12,检查 ClientHello 中的 supported_versions、signature_algorithms、key_share 与 ServerHello 对应字段是否为空或不匹配。第二步:比对服务端 OpenSSL 配置。重点核查:MinProtocol 是否设为 TLSv1.2 以上却未保留兼容套件;CipherString 是否排除了客户端仍广泛使用的 GCM+ECDSA 组合(如 ECDHE-ECDSA-AES128-GCM-SHA256);Options 是否误启用了 NO_TLS1_3_COMPATIBILITY。
第三步:证书链签名一致性检查。运行 openssl x509 -in cert.pem -text -noout | grep "Signature Algorithm",确保叶证书与中间证书签名算法均在客户端 signature_algorithms 列表中。例如,若客户端仅通告 ecdsa_secp256r1_sha256,而中间证书使用 sha384WithRSAEncryption,则握手必然失败。
| 维度 | 参考标准 | 工程师建议 |
|---|---|---|
| 协议版本 | RFC 8446 §B.1, CA/B BR 2.8.2 | 生产服务端应同时启用 TLS 1.2 与 TLS 1.3,MinProtocol TLSv1.2,禁用 TLS 1.0/1.1 |
| 密码套件 | IANA TLS Cipher Suites, Mozilla SSL Config Generator | 优先选用ECDHE-ECDSA-AES128-GCM-SHA256与ECDHE-RSA-AES128-GCM-SHA256,避免 CBC 与 SHA1 |
| 证书签名 | CA/B BR 7.1.3, RFC 5280 §4.1.1.3 | 叶证书推荐 ECDSA P-256 + SHA256;中间证书须与叶证书签名算法兼容,避免混合 RSA/ECDSA 链 |
Q:Chrome 浏览器访问提示 ERR_SSL_VERSION_OR_CIPHER_MISMATCH,但 curl -v 正常,为什么?
A:Chrome 自 2023 年起默认禁用不安全的 legacy crypto(如 TLS 1.2 下的非 AEAD 套件),而 curl 默认使用系统 OpenSSL,可能仍启用兼容模式;需用 curl -v --tlsv1.2 --ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256' 复现 Chrome 行为。
Q:Nginx 配置了 TLS 1.3,但 iOS 14 设备握手失败?
A:iOS 14.0–14.4 存在 TLS 1.3 key_share 扩展解析缺陷,需在 Nginx 中添加 ssl_conf_command Options -UnsafeLegacyRenegotiation; 并降级至 TLS 1.2 兼容模式。
Q:Java 应用连接失败,报 Received fatal alert: handshake_failure?
A:检查 JVM 启动参数是否含 -Djdk.tls.client.protocols=TLSv1.2,并确认 java.security 中 jdk.tls.disabledAlgorithms 未过度限制 EC 算法。
加密您的网站,赢得客户信任!