1. 環境
org.apache.httpcomponents.httpclient 4.5.10版本 + jdk1.8_202版本
2. 問題
需要用HttpClient調用https接口,該https服務器只支持SSLv3,調用時報錯:Received fatal alert: handshake_failure
3. 解決
百度:鋪天蓋地的告訴我如何讓HttpClient繞過SSL認證,包括類似下面的代碼:赫然出現了SSLv3這樣的關鍵字,然並卵
ocketFactory = new SSLConnectionSocketFactory( contextBuilder.build(), new String[]{"TLSv1.2", "SSLv3", "TLSv1", "TLSv1.1"}, null, NoopHostnameVerifier.INSTANCE );
后偶然看到需要更改jdk,因為jdk本身限制了SSLv3協議的使用,也有人說HttpClient根本就不管jdk那一套。遂跑去看源碼:答案是,HttpClient還是符合jdk的設定的。於是解決辦法為:找到你的jre/lib/security下的java.security文件,修改jdk.tls.disabledAlgorithms,把該項配置的SSLv3干掉即可。當然,上面這段代碼還是需要的,詳見org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket方法:關鍵代碼已標紅
if (this.supportedProtocols != null) { sslsock.setEnabledProtocols(this.supportedProtocols); } else { allCipherSuites = sslsock.getEnabledProtocols(); enabledCipherSuites = new ArrayList(allCipherSuites.length); arr$ = allCipherSuites; len$ = allCipherSuites.length; for(i$ = 0; i$ < len$; ++i$) { cipherSuite = arr$[i$]; if (!cipherSuite.startsWith("SSL")) { enabledCipherSuites.add(cipherSuite); } } if (!enabledCipherSuites.isEmpty()) { sslsock.setEnabledProtocols((String[])enabledCipherSuites.toArray(new String[enabledCipherSuites.size()])); } }
4. 最后
只怪自己太垃圾。另附:開啟ssl的bug日志:-Djavax.net.debug=ssl,當然也可以-Djavax.net.debug=all,開啟后如果沒有修改jdk配置,你會看到如下輸出:
Ignoring disabled protocol: SSLv3