Skip to content

Java信任自签名证书

场景

Java程序中访问HTTPS资源,如果使用了自签名证书,大概率会报如下错误:

text
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:1946)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1640)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:167)
	at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:732)
	at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:707)
	at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:297)
	at Test.main(Test.java:22)
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:397)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
	at sun.security.validator.Validator.validate(Validator.java:262)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1622)
	... 18 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:392)
	... 24 more

问题原因

自签名证书需要添加到信任区,但JVM的证书信任区似乎独立于操作系统,所以需要使用keytool工具导入。

解决步骤

  1. 下载证书 比如,使用burpsuite抓包,需要将burpsuite的ca证书下载至本地,假设保存为C:\ca.cer
  2. 导入证书 JVM的keystore默认密码是changeit
    使用administrator身份运行导入命令,比如将C:\ca.cer证书添加到JVM的信任区,并指定别名为burpsuite
shell
& 'C:\Program Files\Java\jdk1.8.0_231\bin\keytool.exe' -import -v -trustcacerts -alias burpsuite -file C:\ca.cer -storepass changeit -keystore 'C:\Program Files\Java\jdk1.8.0_231\jre\lib\security\cacerts'
  1. 验证 方式一: 重新运行Java程序,不会再报SSLHandshakeException;
    方式二: 使用keytool的-list参数;
    shell
    & 'C:\Program Files\Java\jdk1.8.0_231\bin\keytool.exe' -list -keystore 'C:\Program Files\Java\jdk1.8.0_231\jre\lib\security\cacerts' | findstr "burp"

清理

当证书使用完想要移除,可使用如下命令:

shell
& 'C:\Program Files\Java\jdk1.8.0_231\bin\keytool.exe' -delete -alias burpsuite  -keystore 'C:\Program Files\Java\jdk1.8.0_231\jre\lib\security\cacerts'