話不多說,直接上堆疊
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) at sun.security.ssl.Handshaker.process_record(Handshaker.java:961) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496) ... 51 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) ... 57 more
上面是某客戶環境出現的錯誤,從錯誤資訊中大概猜測是https證書出了問題,據開發反饋這個介面使用了近半年,一直沒有問題,我隨即跟運維打探情況,看近期是否有什麼調整。
果然,由於客戶的證書即將到期,所以申請了新證書,昨天晚上剛更新到nginx上去,但是更新完以後客戶、實施都在瀏覽器測試了,並沒有問題,怎麼程式裡HttpClient存取就報錯了呢?
帶著疑問我又測試了curl命令和postman工具,接連失敗,如下圖所示:
機緣巧合下我發現了一個好用的ssl工具網站myssl.com,目前解鎖了兩個很實用的工具,在這裡推薦給大家:
1.網站檢測工具,直接輸入域名然後「立即檢測」
如果證書鏈不完整就會有明確的提示和操作辦法,接著介紹下一個好用的工具。
2.證書補全工具https://myssl.com/chain_download.html,只要輸入域名或者上傳證書檔案就可以自動補全證書鏈,非常好用。
瞭解了上面的兩個ssl工具以後我們這個問題迎刃而解,藉助工具補齊證書鏈然後替換nginx上有問題的證書檔案即可。
本節內容來源於沃通官網的掃盲內容,有興趣的前往推薦閱讀第二條
當我們把SSL證書申請下來時通常會有三個檔案,包括證書的私鑰檔案、證書的公鑰檔案和一個證書鏈檔案,貌似我們把私鑰檔案和公鑰檔案部署到伺服器上就可以了,瀏覽器也正常識別SSL證書,那證書鏈檔案還有什麼用,可以不用嗎,本文就解釋一下證書鏈檔案以及它起到的作用。
一般我們下載的證書有私鑰檔案、公鑰檔案和一個證書鏈檔案,如下圖
雲伺服器申請的證書public檔案就是公鑰開啟也就是我們的網站證書,chain檔案就是證書鏈檔案,key檔案是私鑰,第一個檔案是公鑰和證書鏈檔案合成的檔案。下面是從let's encrypt申請的證書,裡面的key檔案是私鑰,certificate檔案是我的網站的證書其內容就是公鑰,ca_bundle就是證書鏈檔案開啟可以看到CA中間證書。
證書的結構如上圖所示,一般是由CA根證書機構--CA中間證書機構--我們的網站證書構成,中間證書還可能存在多層關係。
系統或瀏覽器中預置了一些受信任的根證書頒發機構和某些中間證書頒發機構,ssl證書在被驗證時最終要驗證其根證書是否可信,網站證書的根證書在瀏覽器可信任根證書列表裡才會被信任或者中間證書頒發機構可信其證書也是可信的,否則瀏覽器則會報告網站的證書來自未知授權中心。可是證書一般是由三級或多級結構構成,瀏覽器是不能通過使用者證書直接驗證其根證書的,這時中間證書即證書鏈檔案起了作用,證書鏈檔案告訴了瀏覽器使用者證書的上級證書機構即中間證書,瀏覽器再通過中間證書驗證其上級根證書是否為可信。
在使用者證書裡面我們會找到這樣的資訊,Authority Info Access(權威資訊存取),通過這裡面的 URL ,我們可以獲得這個證書的頒發者證書,即中間證書。就是說我們在部署SSL證書時沒有把證書鏈檔案(中間證書)部署進去,瀏覽器依然可以通過證書上面的url資訊存取到中間證書,繼而驗證根證書。
本來問題解決完就完事了,但技術人員那顆心哪,就是凡事都要個結果,要不晚上又睡不踏實了。
如果您的業務使用者通過瀏覽器存取您的Web業務,則您無需關注根證書和中間證書,因為根證書和中間證書已經內建在瀏覽器。您只需在Web伺服器安裝經CA簽發的SSL證書,即可實現使用者端與伺服器端的HTTPS通訊。
如果業務使用者通過Java等使用者端存取您的Web業務,由於使用者端沒有內建根證書和中間證書,您可能需要在對應使用者端手動安裝根證書和中間證書,保證使用者端能夠校驗伺服器端的加密資訊。
這是我從阿里雲網站上找到的答案,更多詳細資訊可以前往推薦閱讀第三條。
拍攝於大唐不夜城