SO2O連接報錯javax.net.ssl.SSLException: Received fatal alert: protocol_version)


原文: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

 

 

 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM