Java 應用訪問 HTTPS 服務(如 Azure ServiceBus)時,若目標站點證書不在 JVM 信任存儲中,會拋出經典異常:
javax.net.ssl.SSLException: Connection has been shutdown:
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
將目標站點的 SSL 證書匯入 JVM 信任存儲(cacerts 或 jssecacerts)。
# 從 GitHub 獲取源碼
git clone https://github.com/escline/InstallCert.git
cd InstallCert
javac InstallCert.java
# 語法:java InstallCert [host]:[port]
java InstallCert abc.com:443
執行後會列出證書鏈,輸入編號(通常為 1)確認,當前目錄生成 jssecacerts 檔案。
# 進入 jssecacerts 目錄
keytool -exportcert -alias [host]-1 -keystore jssecacerts -storepass changeit -file [host].cer
# 範例
keytool -exportcert -alias www.abc.com-1 -keystore jssecacerts -storepass changeit -file www.abc.com.cer
# 語法:keytool -importcert -alias [host] -keystore [cacerts路徑] -storepass changeit -file [host].cer
# Windows 範例
keytool -importcert -alias www.abc.com -keystore "C:\Program Files\Java\jre1.8.0_111\lib\security\cacerts" -storepass changeit -file www.abc.com.cer
# Linux 範例
keytool -importcert -alias www.abc.com -keystore /usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/security/cacerts -storepass changeit -file www.abc.com.cer
$ java InstallCert woot.com:443
Loading KeyStore /usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/security/cacerts...
Opening connection to woot.com:443...
Starting SSL handshake...
javax.net.ssl.SSLHandshakeException: ... unable to find valid certification path ...
Server sent 1 certificate(s):
1 Subject O=Woot Inc, C=US, ST=Texas, L=Carrollton, CN=*.woot.com
Issuer CN=SecureTrust CA, O=SecureTrust Corporation, C=US
sha1 4b 46 ca 6b 83 05 b3 51 ff c6 e7 9c fd b3 9b e3 3f 2e c4 53
md5 e8 a5 88 1b d5 67 bb fc 88 cc b1 c5 2b ac c4 7d
Enter certificate to add to trusted keystore or 'q' to quit: [1]
[1]
Added certificate to keystore 'jssecacerts' using alias 'woot.com-1'
$ keytool -exportcert -alias woot.com-1 -keystore jssecacerts -storepass changeit -file woot.com.cer
Certificate stored in file <woot.com.cer>
$ sudo keytool -importcert -alias woot.com -keystore /usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/security/cacerts -storepass changeit -file woot.com.cer
Owner: O=Woot Inc, C=US, ST=Texas, L=Carrollton, CN=*.woot.com
Issuer: CN=SecureTrust CA, O=SecureTrust Corporation, C=US
Trust this certificate? [no]: yes
Certificate was added to keystore
開發/測試/生產環境 JVM 可能不同,需分別配置或構建包含證書的基礎鏡像。
定期檢查證書有效期,過期前重新執行上述流程更新。
// 僅限測試環境使用!
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
System.setProperty("javax.net.ssl.trustStore", "/path/to/custom/cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
掌握證書鏈驗證機制與 keytool 操作,是 Java 後端工程師處理 HTTPS 整合的必備技能。