https如何設置TLS協議版本 javax.net.ssl.SSLException: Received fatal alert: protocol_version)

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)
出現此類錯誤,有可能就是服務端和客戶端協議版本不一致導致的。
程序中可以這樣解決:

第一種方式:

			//以下只貼瞭如何設置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發送請求也和這個代碼類似,就不放示例了

第二種方式:

			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請求,代碼如下:

			//以下只是部分需要展示的代碼
			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());
			
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章