Charlie

[Java] Solve “javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure” exception

N 人看过

問題

在使用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();


參考資訊