环境:
java-1.8.0-openjdk-1.8.0.131
hutool-all 依赖, 5.8.25版本
项目背景:
发版上线,用的hutool工具类 HttpUtil.createPost() ,请求域名为https://xxx.ik3cloud.com/k3cloud 的金蝶ERP webapi接口
问题:
报各类 SSLException 异常.....
原因:
服务端要求的TLS版本,与客户端实际请求的TLS版本不一致
解决过程:
6月19号,在发送post请求前,java代码中明确加上 System.setProperty("https.protocols", "TLSv1.2");代码后,接口能正常调用。
6月24号上午9点27分
日志突然出现大量 : SSLException: Received fatal alert: protocol_version 异常信息....
cn.hutool.core.io.IORuntimeException: SSLException: Received fatal alert: protocol_version
at cn.hutool.http.HttpRequest.send(HttpRequest.java:1350)
at cn.hutool.http.HttpRequest.doExecute(HttpRequest.java:1188)
at cn.hutool.http.HttpRequest.execute(HttpRequest.java:1051)
at cn.hutool.http.HttpRequest.execute(HttpRequest.java:1027)
Caused by: javax.net.ssl.SSLException: Received fatal alert: protocol_version
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2020)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1127)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1334)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1309)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:259)
at cn.hutool.http.HttpConnection.getOutputStream(HttpConnection.java:458)
at cn.hutool.http.HttpRequest.sendFormUrlEncoded(HttpRequest.java:1367)
at cn.hutool.http.HttpRequest.send(HttpRequest.java:1342)
... 8 common frames omitted
引入额外的openjsse依赖 Java8支持TLSv1.3协议请求,问题依旧。。。。。。
于是,查看 该域名用到的TLS具体版本:
yum install nmap
nmap --script ssl-enum-ciphers -p 443 xxx.ik3cloud.com
发现浏览器中 该域名的TLS版本 是1.3 ,但服务器端检查该域名的TLS版本是1.2 ,故项目中的java代码加上如下设置,兼容 TLSv1.2 与 TLSv1.3 版本:
System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
System.setProperty("jdk.tls.client.protocols", "TLSv1.2,TLSv1.3");
运行半小时后,依旧偶尔报错:
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
cn.hutool.core.io.IORuntimeException: SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at cn.hutool.http.HttpRequest.send(HttpRequest.java:1350)
at cn.hutool.http.HttpRequest.doExecute(HttpRequest.java:1188)
at cn.hutool.http.HttpRequest.execute(HttpRequest.java:1051)
at cn.hutool.http.HttpRequest.execute(HttpRequest.java:1027)
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.HandshakeContext.<init>(HandshakeContext.java:171)
at sun.security.ssl.ClientHandshakeContext.<init>(ClientHandshakeContext.java:106)
at sun.security.ssl.TransportContext.kickstart(TransportContext.java:245)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:410)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:389)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:558)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:201)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1390)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1365)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:264)
at cn.hutool.http.HttpConnection.getOutputStream(HttpConnection.java:458)
at cn.hutool.http.HttpRequest.sendFormUrlEncoded(HttpRequest.java:1367)
at cn.hutool.http.HttpRequest.send(HttpRequest.java:1342)
... 7 common frames omitted
java代码中,使用与金蝶ERP服务器一致的加密套件,
# 通过如下命令,查询金蝶服务器端所用的加密套件
openssl s_client -connect XXX.ik3cloud.com:443 -tls1_2
// 使用与金蝶服务端 一致的加密套件
System.setProperty("https.cipherSuites", "ECDHE-RSA-AES256-GCM-SHA384");
也依旧报Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
于是向金蝶客服提工单,金蝶技术建议用JDK11:
于是升级jdk为 open jdk11.0.2 ,刚开始正常,半个小时后 偶发性的报错 Caused by: javax.net.ssl.SSLException: No PSK available. Unable to resume.
javax.net.ssl.SSLException: No PSK available. Unable to resume.
原因jdk11版本过低: 这是一个jdk11的已知bug:https://bugs.openjdk.java.net/browse/JDK-8213202
最后使用jdk11的最新版本: oracle jdk11.0.27 ,再无以上SSLException异常,
至此,问题解决
附录:
Java默认使用的协议版本