Java (JSSE)Java
错误信息
javax.net.ssl.SSLHandshakeException: (protocol_version) Received fatal alert: protocol_version
也可能输出为
- javax.net.ssl.SSLHandshakeException: Received fatal alert: protocol_version
JDK 21 及更高版本会在括号中包含告警名称。如果服务器没有拒绝,而是选择了 JVM 不接受的版本,Java 会报出“The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]”。
Java (JSSE) — TLS alert 70 received from the server
含义
服务器拒绝了 JVM 提供的 TLS 版本,并以告警 70(protocol_version)作出回应。当前的 JDK 只提供 TLS 1.3 和 1.2(1.0 和 1.1 在 jdk.tls.disabledAlgorithms 中),因此只支持旧版本的服务器与它们没有共同的版本。
原因
服务器只支持 TLS 1.0 或 1.1
常见从未升级到 TLS 1.2 的老旧硬件设备、旧版 IIS 或 Java 服务器以及嵌入式设备。
客户端固定使用服务器已禁用的版本
偶见旧的启动脚本为某个早已下线的旧系统,把 https.protocols 或 jdk.tls.client.protocols 设置成了 TLSv1;现代服务器会拒绝这样的连接。
修复方法
- 1.
找出服务器接受的版本
用 openssl s_client 逐个探测各个版本,然后修复版本过时的那一方。
bash for v in tls1 tls1_1 tls1_2 tls1_3; do printf '%-7s ' "$v" echo | openssl s_client -connect legacy.example.com:443 -servername legacy.example.com -"$v" \ -cipher 'DEFAULT:@SECLEVEL=0' >/dev/null 2>&1 && echo accepted || echo refused done - 2.
去掉客户端上固定的协议版本
在启动脚本和 JVM 选项中查找 https.protocols 或 jdk.tls.client.protocols;允许 TLSv1.3 和 TLSv1.2。
bash # Do not pin old versions on the client; let JSSE offer 1.3 and 1.2 grep -rn 'https.protocols\|jdk.tls.client.protocols' /etc/default/app* "$JAVA_HOME/conf" 2>/dev/null java -Djdk.tls.client.protocols=TLSv1.3,TLSv1.2 -jar app.jar - 3.
在服务器上启用 TLS 1.2 和 1.3
这是长久之计:所有仍在维护的客户端都支持这两个版本。
text # Server side: enable TLS 1.2 and 1.3 ssl_protocols TLSv1.2 TLSv1.3;