前陣子在做安全協定升級,從 HTTP over SSL 升級為 HTTP over TLS v1.1、TLS v1.2。
新服務僅允許使用 TLS v1.2 Protocol ,因為 Google 早在 2014年10月就發布在 SSL 3.0 中發現設計缺陷,建議禁用此一協議。詳情請看 wiki。
這時候發現個問題 JDK 各版本對於 TLS Protocols 支援不同,如下表。
JDK 8. (March 2014 to present) | JDK 7. (July 2011 to present) | JDK 6. (2006 to end of public updates 2013) | |
---|---|---|---|
TLS Protocols | TLSv1.2 (default)、TLSv1.1、TLSv1、SSLv3 | TLSv1.2、TLSv1.1、TLSv1 (default)、SSLv3 | TLS v1.1(JDK 6 update 111 and above)、TLSv1 (default)、SSLv3 |
因為 JDK 6 dafault 是 TLSv1,並且不支援 TLS v1.2,除非升級至 JDK 6u121(need support contract)。
所以當使用 JDK 6 or 7 的程式要去呼叫使用 HTTP over TLS v1.2 Protocol 的位置時,就會出現以下錯誤
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:946)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1091)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at com.labcorp.efone.vendor.TestATTConnectivity.main(TestATTConnectivity.java:43)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at sun.security.ssl.InputRecord.read(InputRecord.java:482)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927)
... 8 more
這個錯誤的意思是遠端服務在交握時關閉連線,這個錯在 StackOverflow 也有答案了,參考此。
解決方法有幾種:
- 啟動服務時,設定 https.protocols 環境變數,讓 JVM 啟動時載入 HttpsURLConnection;
-Dhttps.protocols=TLSv1.1,TLSv1.2
- 建立連線前,設定 https.protocols 環境變數;
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
- Customizing SSL in HttpClient 3.x
- 升級至 JDK 8
沒有留言:
張貼留言