[Java] Solve “javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure” exception
問題
在使用JBoss resteasy呼叫api的時候出現
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
查了資料後發現,會出現這個原因是應該是因為Client端跟Server端的協議版本不一至導致
Nmap
先安裝一下nmap
brew install nmap
nmap是一款網路的安全工具
官方介紹:
Nmap (“Network Mapper”) is a free and open source utility for network discovery and security auditing.
這邊我用來檢查server端的協議版本
nmap --script ssl-enum-ciphers -p 443 你的server端位置
Starting Nmap 7.92 ( <https://nmap.org> ) at 2022-09-02 09:50 CST
Nmap scan report for 你的server端位置
Host is up (0.10s latency).
Other addresses for 你的server端位置
PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers:
| TLSv1.0:
| TLSv1.1:
|_ TLSv1.2:
看起來是支援TLS1.0, TLS1.1, TLS1.2
接著看一下client端用的協議版本
在java code中加入
System.setProperty("javax.net.debug", "all");
再次呼叫之後可以看到以下某一行的輸出
...
Thread-1, WRITE: SSLv2 client hello message, length = 110
...
看起來是client端有上使用到SSLv2的協議版本
但是server端不支援
因為專案的項目是使用jdk6
更換成jdk7後就沒問題了
更新:2022/10/25
其他問題
後來還是有遇到其他jdk ssl協定版本不同的問題
只能透過另一種方式處理
hostnameVerifier
這邊使用的是Resteasy的API操作
可以參考以下這篇
在透過ClientBuilder產生Client的實體的時候
複寫HostnameVerifier的verify
Java Code
// skip host name validate
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[] { new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
} }, new java.security.SecureRandom());
HostnameVerifier allowAll = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
Client client = ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier(allowAll).build();
參考資訊
- oracle
- blog
- stackoverflow
- other