案例分享-https證書鏈不完整導致請求失敗

背景

話不多說,直接上堆棧

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.證書補全工具//myssl.com/chain_download.html,只要輸入域名或者上傳證書文件就可以自動補全證書鏈,非常好用。

 

 

 

 了解了上面的兩個ssl工具以後我們這個問題迎刃而解,藉助工具補齊證書鏈然後替換nginx上有問題的證書文件即可。

https證書鏈的作用

本節內容來源於沃通官網的掃盲內容,有興趣的前往推薦閱讀第二條

當我們把SSL證書申請下來時通常會有三個文件,包括證書的私鑰文件、證書的公鑰文件和一個證書鏈文件,貌似我們把私鑰文件和公鑰文件部署到伺服器上就可以了,瀏覽器也正常識別SSL證書,那證書鏈文件還有什麼用,可以不用嗎,本文就解釋一下證書鏈文件以及它起到的作用。

SSL證書的構成

一般我們下載的證書有私鑰文件、公鑰文件和一個證書鏈文件,如下圖

 

 

 

雲伺服器申請的證書public文件就是公鑰打開也就是我們的網站證書,chain文件就是證書鏈文件,key文件是私鑰,第一個文件是公鑰和證書鏈文件合成的文件。下面是從let’s encrypt申請的證書,裡面的key文件是私鑰,certificate文件是我的網站的證書其內容就是公鑰,ca_bundle就是證書鏈文件打開可以看到CA中間證書。

 

 

 證書的結構如上圖所示,一般是由CA根證書機構–CA中間證書機構–我們的網站證書構成,中間證書還可能存在多層關係。

瀏覽器驗證SSL證書

系統或瀏覽器中預置了一些受信任的根證書頒發機構和某些中間證書頒發機構,ssl證書在被驗證時最終要驗證其根證書是否可信,網站證書的根證書在瀏覽器可信任根證書列表裡才會被信任或者中間證書頒發機構可信其證書也是可信的,否則瀏覽器則會報告網站的證書來自未知授權中心。可是證書一般是由三級或多級結構構成,瀏覽器是不能通過用戶證書直接驗證其根證書的,這時中間證書即證書鏈文件起了作用,證書鏈文件告訴了瀏覽器用戶證書的上級證書機構即中間證書,瀏覽器再通過中間證書驗證其上級根證書是否為可信

在用戶證書裡面我們會找到這樣的資訊,Authority Info Access(權威資訊訪問),通過這裡面的 URL ,我們可以獲得這個證書的頒發者證書,即中間證書。就是說我們在部署SSL證書時沒有把證書鏈文件(中間證書)部署進去,瀏覽器依然可以通過證書上面的url資訊訪問到中間證書,繼而驗證根證書。

 

 

其他工具訪問有問題,偏偏瀏覽器正常

本來問題解決完就完事了,但技術人員那顆心哪,就是凡事都要個結果,要不晚上又睡不踏實了。

如果您的業務用戶通過瀏覽器訪問您的Web業務,則您無需關注根證書和中間證書,因為根證書和中間證書已經內置在瀏覽器。您只需在Web伺服器安裝經CA簽發的SSL證書,即可實現客戶端與服務端的HTTPS通訊。

如果業務用戶通過Java等客戶端訪問您的Web業務,由於客戶端沒有內置根證書和中間證書,您可能需要在對應客戶端手動安裝根證書和中間證書,保證客戶端能夠校驗服務端的加密資訊。

這是我從阿里雲網站上找到的答案,更多詳細資訊可以前往推薦閱讀第三條。

 

推薦閱讀

myssl

沃通掃盲

阿里雲資料01

阿里雲資料02

 

拍攝於大唐不夜城