原文:https://blog.csdn.net/gudejundd/article/details/89640741
1.什么是TLS
SSL 是“Secure Sockets Layer”的縮寫,中文叫做“安全套接層”。它是在上世紀90年代中期,由網景公司設計的。(順便插一句,網景公司不光發明了 SSL,還發明了很多 Web 的基礎設施——比如“CSS 樣式表”和“JS 腳本”)
為啥要發明 SSL 這個協議捏?因為原先互聯網上使用的 HTTP 協議是明文的,存在很多缺點——比如傳輸內容會被偷窺(嗅探)和篡改。發明 SSL 協議,就是為了解決這些問題。
到了1999年,SSL 因為應用廣泛,已經成為互聯網上的事實標准。IETF 就在那年把 SSL 標准化。標准化之后的名稱改為 TLS(是“Transport Layer Security”的縮寫),中文叫做“傳輸層安全協議”。
很多相關的文章都把這兩者並列稱呼(SSL/TLS),因為這兩者可以視作同一個東西的不同階段。
2.TLS有哪些版本、JDK默認支持哪些版本
TLS版本有: SSLv2、 SSLv3、 TLSv1、 TLSv1.1、 TLSv1.2
其中 SSLv2、SSLv3應該沒有在用的,一些公司都已經禁用
TLSv1、TLSv1.1 目前還有公司在用,不過很過公司開始陸續禁用。
JDK支持的tls版本:
在這里插入圖片描述
3.java程序中如何指定TLS版本?
目前從JDK1.8開始都默認TLSv1.2協議了,但對於還在用版本低的JDK時,如果服務端禁用了TLSv.1 ,而代碼中沒有指定具體協議版本,那么JDK都是采用默認版本建立連接。這樣會出現以下錯誤:
javax.net.ssl.SSLException: Received fatal alert: protocol_version)
出現此類錯誤,有可能就是服務端和客戶端協議版本不一致導致的。
程序中可以這樣解決:
第一種方式:(SF代碼不全不好用)
//以下只貼了如何設置tls版本號的代碼 SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); //這邊指定tls版本 sslContext.init(kmf.getKeyManagers(),tm, null); SSLSocketFactory factory = sslContext.getSocketFactory(); URL url = new URL(merchantInfo.getUrl()); HttpsURLConnection urlc = (HttpsURLConnection) url.openConnection(); urlc.setSSLSocketFactory(factory); //這一步很重要
采用httpClient發送請求也和這個代碼類似,就不放示例了
第二種方式:(SF好用,直接加到client create前就行)
SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null,null,null); SSLContext.setDefault(sslContext);
第二種方式setDefault是全局性的,相當於整個程序如果沒有指定TLS版本,那么默認都采用1.2,會影響程序中其它使用默認TLS版本的地方,比如:之前使用默認TLSv1.0版本的,如果你設置了setDefault()變成1.2了,如果服務端不支持1.2協議會發生異常,不過現在應該沒有不支持1.2協議的,所以大家自己考慮采用哪種方式。
還有人說用了第二種方式不起作用,那么我解釋一下:
比如使用JDK自帶的HttpsURLConnection發送https請求,代碼如下:(sf不知道怎麽用,沒試過)
//以下只是部分需要展示的代碼 URLConnection connection = url.openConnection(); //這一步回去創建連接,這時候會調用SSLContext.getDefault().getSocketFactory(); 會返回我們上面設置的TLSv1.2協議SSLSocketFactory,這樣我們setDefault()方法是有效的。 HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection; httpsURLConnection.setRequestMethod(HttpTransportConstants.METHOD_POST); httpsURLConnection.setUseCaches(false); httpsURLConnection.setDoInput(true); httpsURLConnection.setDoOutput(true); httpsURLConnection.setConnectTimeout(getConnectTimeout()); httpsURLConnection.setReadTimeout(getReadTimeout());*/ //不過有些程序會有如下代碼,SSLSocketFactory又重新設置了一遍, SSLContext.getInstance("ssl");獲取的是TLSv1.0協議,這樣又使用了TLS1.0協議進行通訊了,就不會起到效果,其實下面這點代碼就是第一種方式介紹的。 SSLContext sc = SSLContext.getInstance("ssl"); sc.init(null, null, new java.security.SecureRandom()); httpsURLConnection.setSSLSocketFactory(sc.getSocketFactory());
原文2:https://blog.csdn.net/bbc2005/article/details/80890829
解決辦法
1:把JDK升級到1.8。由於該網站使用的是TLSv1.2協議,JDK1.8默認是該協議,故把客戶端JDK升級到1.8可以解決該問題。
2:在JDK1.7客戶端代碼中指定使用的協議System.setProperty("https.protocols", "TLSv1.2") →(SF親測好用)
或
System.setProperty("jdk.tls.client.protocols", "TLSv1.2") →(SF親測不好用)。注意,該方法有時候會莫名的失效,原因未知。
3:在VM參數中設置-Dhttps.protocols=TLSv1.2或-Djdk.tls.client.protocols=TLSv1.2。注意,該方法有時候會莫名的失效,原因未知。(sf未測試,不會用)
4:使用第三方庫了,參考http://ligaosong.iteye.com/blog/2356346
5:使用httpclient,其支持配置使用指定協議
原文3:https://blog.csdn.net/Blade_/article/details/97491193
因面臨Oracle旗下NetSuite雲ERP密碼套件的升級(安全傳輸層協議由之前的TLS v1.1升級到TLS v1.2),導致我司WMS與ERP系統接口無法正常使用,具體報錯如下:
后經查閱資料,發現jdk1.7是默認采用的TLS v1.1和TLSv1.0版本的,因此只需采用如下操作即可解決:(SF:和上面好用的“第二種方法”其實本質相同,多了Try catch更好了)
try { SSLContext ctx = SSLContext.getInstance("TLSv1.2"); ctx.init(null, null, null); SSLContext.setDefault(ctx); //將你所要使用的TLS版本設為默認 } catch (NoSuchAlgorithmException e1) { e1.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } System.setProperty("https.protocols", "TLSv1.2");
原文4:java.lang.ClassNotFoundException: com.ibm.websphere.ssl.protocol.SSLSocketFactory的解決辦法
Websphere8.5 + IBM JDK 下訪問HTTPS/SSL 出現java.lang.ClassNotFoundException: com.ibm.websphere.ssl.protocol.SSLSocketFactory的解決辦法
第一種方法:在程序初始化的時候加入以下代碼:
//solve the error: java.lang.ClassNotFoundException: com.ibm.websphere.ssl.protocol.SSLSocketFactory Security.setProperty("ssl.SocketFactory.provider", ""); Security.setProperty("ssl.ServerSocketFactory.provider", "");
(SF,這個ClassNotFoundException的錯誤最初是沒有的,當我爲了測試TLS1.2把RAD的jdk從1.6變成1.7,又變回1.6后出現了,然後就必須加上面這段代碼才好用)
根據Oracle文檔知各版本JDK默認使用的TLS協議如下:
https://blogs.oracle.com/java-platform-group/diagnosing-tls,-ssl,-and-https
2019年11月18日 使用apache解決這個問題:
參考:
1,官方sample代碼:
https://hc.apache.org/httpcomponents-client-4.5.x/examples.html
2,jar包下載地址(官方)
http://hc.apache.org/downloads.cgi