本文檔深入剖析了Java用戶端因伺服器未提供完整憑證鏈結而導致“unable to find valid certification path”的HTTPS訪問失敗問題,並提供使用openssl排查及在服務端配置完整憑證鏈結的實用解決方案。
問題現象
Java應用程式通過HTTPS訪問服務端點時,串連失敗並拋出javax.net.ssl.SSLHandshakeException異常,核心錯誤資訊如下:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target該問題通常伴隨以下現象:
瀏覽器訪問正常:使用主流瀏覽器(如Chrome、Firefox)訪問同一HTTPS地址,串連成功且顯示安全鎖標誌。
部分用戶端失敗:Java應用程式、
curl、wget等非瀏覽器用戶端訪問時,均報告TLS握手失敗或認證驗證錯誤。
問題原因
SSL/TLS協議依賴一個從伺服器憑證到用戶端信任的根憑證的完整“信任鏈結”。此錯誤的根本原因是Java用戶端無法構建出這條完整的信任鏈結。
原因一:伺服器未提供完整的憑證鏈結
伺服器在TLS握手時,僅發送了伺服器憑證(網域名稱認證),但遺漏了必要的中間認證。大多數非瀏覽器用戶端(包括Java)預設不具備從網路自動下載缺失認證的能力,導致驗證失敗。而現代瀏覽器具備AIA(Authority Information Access) chasing功能,可自動下載缺失的中間認證以補全憑證鏈結,因此訪問正常。
原因二:用戶端JDK信任庫過舊
伺服器已正確配置並發送了完整憑證鏈結,但憑證鏈結的根憑證(或交叉簽名的根憑證)未被用戶端的JDK信任。通常發生在用戶端JDK版本過舊,其內建的信任庫(
$JAVA_HOME/jre/lib/security/cacerts)不包含新版根憑證(例如,DigiCert從G1根切換到G2根後,舊版JDK可能不信任G2根),詳情可參考關於DigiCert根替換公告。
解決方案
排查此問題應遵循“先服務端,後用戶端”的順序。首先使用openssl命令診斷伺服器配置,確認憑證鏈結是否完整。若服務端配置無誤,再檢查用戶端環境。
步驟一:檢查伺服器憑證鏈配置
此步驟用於確認伺服器在TLS握手時是否發送了完整的憑證鏈結。
在任意一台已安裝OpenSSL的裝置上,執行以下命令。將
your.domain.com:443替換為實際的服務端點地址和連接埠。# 串連伺服器並顯示其提供的憑證鏈結 openssl s_client -connect your.domain.com:443 -showcerts分析命令輸出中的
Certificate chain部分和Verify return code。問題情境(憑證鏈結不完整)
輸出中僅有一個以
depth=0開頭的認證,且末尾的驗證返回碼非0,通常為Verify return code: 20 (unable to get local issuer certificate)。這明確表示伺服器未提供中間認證。Certificate chain 0 s:/CN=your.domain.com i:/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1 --- Server certificate -----BEGIN CERTIFICATE----- (伺服器憑證內容) -----END CERTIFICATE----- ... Verify return code: 20 (unable to get local issuer certificate)正常情境(憑證鏈結完整)
輸出中包含多個認證,形成從
depth=0(伺服器憑證)到depth=1(中間認證)的有序鏈條。驗證返回碼為Verify return code: 0 (ok)。Certificate chain 0 s:/CN=your.domain.com i:/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1 1 s:/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1 i:/C=US/O=DigiCert Inc/CN=DigiCert Global Root CA --- ... Verify return code: 0 (ok)
步驟二:修複問題
根據步驟一的診斷結果,執行對應的修複操作。
情境一:修複不完整的伺服器憑證鏈
若openssl診斷結果為憑證鏈結不完整,需在伺服器端(如Nginx、Apache、Tomcat、Server Load Balancer等)重新設定認證。
從憑證授權單位(CA)擷取包含伺服器憑證和所有中間認證的認證包檔案。該檔案通常命名為
fullchain.pem或chain.pem。確保認證包檔案內容遵循以下順序:伺服器憑證在前,中間認證在後。
-----BEGIN CERTIFICATE----- (您的伺服器憑證內容) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- (中間認證1的內容) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- (中間認證2的內容,如果存在) -----END CERTIFICATE-----參考您的Web伺服器或網關的官方文檔,將其SSL認證配置指向此完整的認證包檔案,然後重啟服務使配置生效。
情境二:處理用戶端JDK信任庫問題
若openssl診斷結果顯示伺服器憑證鏈完整,但Java用戶端依然報錯,則問題很可能源於用戶端JDK版本過舊。
推薦方案:升級JDK 將用戶端應用的JDK升級至最新的長期支援(LTS)版本(如JDK 8、11、17的最新更新版)。新版JDK包含了最新的根憑證庫,能解決因CA根憑證更替導致的問題,同時也能獲得重要的安全修複和效能提升。
臨時方案:手動匯入根憑證至信任庫 若無法立即升級JDK,可手動將缺失的根憑證匯入到當前JDK的
cacerts信任庫中。擷取缺失的根憑證檔案,可參考下載根憑證。
執行以下
keytool命令將其匯入。預設密碼為changeit。# 將<path-to-root-ca.crt>替換為根憑證檔案路徑 # 將$JAVA_HOME替換為您的Java安裝目錄 keytool -import -alias <give-a-unique-alias> -keystore $JAVA_HOME/jre/lib/security/cacerts -file <path-to-root-ca.crt> -storepass changeit
後續建議
配置最佳化:將認證更新流程標準化。在每次更新認證時,都必須驗證並部署完整的憑證鏈結檔案,而非僅部署網域名稱認證檔案。
監控警示:購買並開啟公網網域名稱監控,定期探測HTTPS服務的認證狀態,避免認證到期導致網站不可用。