如果是使用 JDK1.8,其支持 TLSv1.2,並且且預設就使用 TLSv1.2 來進行 HTTPS 的連線,
寫法可以參考之前寫的這篇文章 "以Java 由Url下載圖片" 裡面的 "getHttpURLConnectionFromHttps()" 方法來進行 HTTPS 的請求。
但是例如如果為較舊的 JDK1.5,則沒有支持 TLSv1.2,此時還用 JDK1.8的寫法去請求 TLSv1.2的server時,就會產生錯誤。
在這篇文章中,我紀錄了我找到的方法,如何讓 JDK1.5 也能進行對 TLSv1.2 server的請求。
=================================
我使用的JDK為 jdk1.5.0_22
測試的網站為 https://fancyssl.hboeck.de/
此網站聲稱只為TLSv1.2的request開放
可以使用線上SSL檢測工具來查看此網站的SSL相關設定
https://www.ssllabs.com/ssltest/analyze.html?d=fancyssl.hboeck.de
需要的 jar
- Bouncy Castle 的 Library :
- Provider
- DTLS/TLS API/JSSE Provider
- 解開Java密鑰長度限制的
"Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files" - JDK 1.5 可到這裡下載 "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0"。
步驟:
- 導入Bouncy Castle的 jar
Bouncy Castle 是一個提供許多密碼演法等的 Java Library,而 TLSv1.2 跟 舊版的差別其中就有密碼演算等不同,其中更深的原理我沒有鑽研,在此只展示找到的可行解決方案。
首先先到 Bouncy Castle官網 下載 Provider 及 DTLS/TLS API/JSSE Provider 的 jar 檔,我這邊選擇的為 bcprov-jdk15on-159.jar 和 bctls-jdk15on-159.jar。 請下載並加到 Java 專案的 Library中。
- 測試程式進對指定的url進行TLSv1.2 HTTPS 請求,並將回應印出來,在這裡會將整個網頁的源始碼印出來。
測試程式碼如下:import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.SecureRandom; import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; public class HttpsClientRequestTest { public static void main(String[] args) throws Exception { Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); Security.insertProviderAt(new BouncyCastleProvider(), 1); Security.removeProvider(BouncyCastleJsseProvider.PROVIDER_NAME); Security.insertProviderAt(new BouncyCastleJsseProvider(), 2); /* * TEST CODE ONLY. If writing your own code based on this test case, you should configure * your trust manager(s) using a proper TrustManagerFactory, or else the server will be * completely unauthenticated. */ TrustManager tm = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { //do nothing } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { //do nothing } }; HostnameVerifier customHostnameVerifier = new HostnameVerifier() { public boolean verify(String arg0, SSLSession arg1) { return true; } }; SSLContext sslContext = SSLContext.getInstance("TLSv1.2", BouncyCastleJsseProvider.PROVIDER_NAME); sslContext.init(null, new TrustManager[]{ tm }, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(customHostnameVerifier); HttpURLConnection httpUrlConnection = (HttpURLConnection) (new URL("https://fancynossl.hboeck.de")).openConnection(); httpUrlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.2.1; Nexus 7 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19"); httpUrlConnection.connect(); InputStream is = null; if (httpUrlConnection.getResponseCode() >= 400) { is = httpUrlConnection.getErrorStream(); } else { is = httpUrlConnection.getInputStream(); } BufferedReader responseBufferedReader = new BufferedReader((new InputStreamReader(is))); StringBuffer responseTextStringBuffer = new StringBuffer(); String tempString = null; while((tempString = responseBufferedReader.readLine()) != null) { responseTextStringBuffer.append(tempString + "\n"); } String responseText = responseTextStringBuffer.toString(); httpUrlConnection.disconnect(); System.out.println(responseText); } }
- 因為還沒有開放 Java 的密鑰長度限制,所以應該會出現以下錯誤java.security.InvalidKeyException: Illegal key sizeException
此時將下載的 "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0" 裡面的 "local_policy.jar" 和 "US_export_policy.jar" 覆蓋到JAVA_HOME\jre\lib\security\ 之下的 "local_policy.jar" 和 "US_export_policy.jar" ,再執行一次,應該就會成功了。
下載頁面如圖所示:
參考資料:
沒有留言 :
張貼留言