1. 程式人生 > >javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake 痛苦解決之旅

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake 痛苦解決之旅

 

上週另外一專案組的同事找到我說,遇到一個問題很棘手兩天了還沒解決掉,報錯如下:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:980) ~[na:1.8.0_45]
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363) ~[na:1.8.0_45]
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391) ~[na:1.8.0_45]
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375) ~[na:1.8.0_45]
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563) ~[na:1.8.0_45]
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) ~[na:1.8.0_45]
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153) ~[na:1.8.0_45]
        at com.dangdang.ddframe.job.executor.type.SimpleJobExecutor.process(SimpleJobExecutor.java:41) [elastic-job-common-core-2.1.5.jar:na]
        at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.process(AbstractElasticJobExecutor.java:206) [elastic-job-common-core-2.1.5.jar:na]
        at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.process(AbstractElasticJobExecutor.java:171) [elastic-job-common-core-2.1.5.jar:na]
        at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.execute(AbstractElasticJobExecutor.java:150) [elastic-job-common-core-2.1.5.jar:na]
        at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.execute(AbstractElasticJobExecutor.java:122) [elastic-job-common-core-2.1.5.jar:na]
        at com.dangdang.ddframe.job.lite.internal.schedule.LiteJob.execute(LiteJob.java:26) [elastic-job-lite-core-2.1.5.jar:na]
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [quartz-2.2.1.jar:na]
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.2.1.jar:na]
Caused by: java.io.EOFException: SSL peer shut down incorrectly
        at sun.security.ssl.InputRecord.read(InputRecord.java:505) ~[na:1.8.0_45]
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:961) ~[na:1.8.0_45]
        ... 21 common frames omitted

據同事表述:這個是他們用httpclient 呼叫三方的一個https的介面,在本地單元測試沒問題,用瀏覽開啟也沒問題。

因為之前遇到類似問題,就很自信的在網路上找相關的解決方案,找了好多方案,例如:System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");

再如:SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); 都不行。

還有說是jdk 1.7 才會有這個問題,但是我們的環境本身就是1.8. 看著別人的評論通過這些方法多少都解決了問題,我們是真越發的著急了,

想來想去,三方介面沒動,環境也沒動,我們本地行,測試環境不行,又覺得是環境問題,又看了一下jdk版本,本地是1.8.0_131,測試環境是1.8.0_45 ,想到會不是這個問題,就把本地jdk做了降級到45 ,可悲的是並沒有在本地重現測試環境問題,這時候,我們只能懷疑是網路問題,怎麼查呢?抓包。

抓包 下來後,我們對比了本地的包,測試環境的包確實發現些問題,測試環境的包截圖如下:

tcp三次握手後,客戶端發了個 Client hello ,但是服務端確返回了,Handshake Failure  問題肯定是出這裡,對比這個包,跟正常的包,反覆對比後,還是沒能看到問題來,於是找到了網路同事,網路同事也是協助一起檢視。

終於找到了這麼一個帖子:Java加密套件強度限制引起的SSL handshake_failure 我對比了下,情況幾乎一樣,我把作者查詢問題的方法都試了一遍(驗證方法可以參考上面的帖子,不再贅餘),也都一致,最終我們嘗試了作者給出的方法 :

升級jdk到 1.8.0_151和以後的版本,無需下載任何檔案,只要修改Java\jre\lib\security\java.security檔案

crypto.policy=unlimited

這次真真的問題解決了,在這裡也謝謝這位作者!

到這裡還沒完,這種方式,還是要修改jdk的配置檔案,考慮到線上環境都是統一,修改檔案會使得jdk變的不統一,我又嘗試著找看看有沒有更好的辦法,果然,又看到另外一個文章:JCE policy changes in Java SE 8u151, 8u152 and 8u162 文章裡說“Oracle released Java 8 u162. In this version the unlimited policy is enabled by default. You no longer need to install the policy file in the JRE or set the security property crypto.policy.”

jdk1.8.0_162 之上的版本已經將crypto.policy 預設設定為unlimited 於是我們索性直接將jdk升級到1.8的最終更新Java SE 8u181 到此問題總算處理完了!

這個bug: JDK-8170157

總結一下:

問題的最終解決,算不上自己一步步解決掉,參考了前人的大多文章,這裡想說的是解決問題的方法和思路:

1.一定要堅持,好多問題有些同事,上網找找沒有辦法就不幹了

2.先思考,自己解決,處理不了,多上網找找資料,互聯可能是會陪伴我們終生的老師,好好借用

3.這裡面用到了好多的網路知識,和處理網路問題的辦法,比如,tcp,ssl/tls ,Handshake,抓包等等,可能作為一個開發人員會覺得這些離我們很遠,我們跟本用不到,只用java 編碼就行了,只會crud,能完成開發功能就可以了,我只能說那麼你這一輩子也就只能當個初級程式設計師!!!

抽午休時間總結了一下,希望對大家有所幫助!