解决 javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
运行环境 tomcat9.0+jdk11
我用tomcat1上的程序去访问本机的tomcat2上的程序报错:javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target。我的程序是这样的:
try { HttpClient client = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .build(); java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder() .uri(URI.create(urlStr)) .timeout(Duration.ofSeconds(10)) // 设置超时时间,可根据实际情况调整 .GET() .build(); String jsonString = ""; try { HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(urlStr + "==" + jsonString); jsonString = response.body(); } catch (IOException | InterruptedException e) { e.printStackTrace(); }
解决方案一:创建了一个自定义的TrustManager,它会信任所有的证书,在测试环境中可以快速解决证书验证问题,但在生产环境中会带来安全风险,因为它不进行真正的证书验证,容易受到中间人攻击
这里的`storepass`是`cacerts`文件的默认密码`changeit`。
- **方法二:配置自定义SSLContext(更灵活,适用于复杂场景)**
- **创建自定义TrustManager(信任所有证书,仅用于测试,有安全风险)**:
```java
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.http.HttpClient;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
//...
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.sslContext(sslContext)
.build();
java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()
.uri(URI.create(urlStr))
.timeout(java.time.Duration.ofSeconds(10))
.GET()
.build();
String jsonString = "";
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(urlStr + "==" + jsonString);
jsonString = response.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
二:正确配置 TrustManager(使用服务器证书进行验证)
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
//...
try {
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("keystore.jks");
keyStore.load(fis, "password".toCharArray());
fis.close();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.sslContext(sslContext)
.build();
// 后续代码与之前的HttpRequest和HttpResponse处理相同
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | KeyManagementException e) {
e.printStackTrace();
}
浙公网安备 33010602011771号