如何忽略 PKIX 路径构建失败: sun.security.provision. certpath. SunCertPathBuilderException?

当尝试向 http 服务器发送请求时,我遇到了以下异常:

这是我用的代码

URL url = new URL(
"https://www.abc.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();


conn.setRequestMethod("GET");


conn.setDoOutput(true);


DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
// wr.writeBytes(params);
wr.flush();
wr.close();


BufferedReader br = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}

这里有一个例外:

Exception in thread "main" 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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1014)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
at com.amazon.mzang.tools.httpchecker.CategoryYank.getPV(CategoryYank.java:32)
at com.amazon.mzang.tools.httpchecker.CategoryYank.main(CategoryYank.java:18)
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:323)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
... 13 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
... 19 more

服务器不属于我。有办法忽略这个异常吗?

468002 次浏览

如果您想忽略所有证书,那么请看这里的答案: 使用 Jersey Client 忽略自签名的 ssl 证书

虽然这会使你的应用程序容易受到中间人攻击。

或者,尝试将 cert 作为受信任的 cert 添加到 Java 存储中。 这个网站可能会有帮助。 Http://blog.icodejava.com/tag/get-public-key-of-ssl-certificate-in-java/

下面是另一个演示如何向商店添加证书的线程。 JavaSSL 连接,以编程方式将服务器证书添加到密钥存储库

关键是:

KeyStore.Entry newEntry = new KeyStore.TrustedCertificateEntry(someCert);
ks.setEntry("someAlias", newEntry, null);

我已经使用下面的代码来覆盖我的项目中的 SSL 检查,它对我很有效。

package com.beingjavaguys.testftp;


import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;


import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;


/**
* Fix for Exception in thread "main" 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
*/
public class ConnectToHttpsUrl {
public static void main(String[] args) throws Exception {
/* Start of Fix */
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }


} };


SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());


// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) { return true; }
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/* End of the fix*/


URL url = new URL("https://nameofthesecuredurl.com");
URLConnection con = url.openConnection();
Reader reader = new InputStreamReader(con.getInputStream());
while (true) {
int ch = reader.read();
if (ch == -1)
break;
System.out.print((char) ch);
}
}
}

JSoup命令将 validateTLSCertificates属性设置为 false

Jsoup.connect("https://google.com/").validateTLSCertificates(false).get();

FWIW,在 Ubuntu 10.04.2 LTS 上,安装 ca 证书-java 和 ca 证书包为我解决了这个问题。

我在执行下面的 spring-boot + RestAssure 简单测试时也出现了同样的错误。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


import static com.jayway.restassured.RestAssured.when;
import static org.apache.http.HttpStatus.SC_OK;


@RunWith(SpringJUnit4ClassRunner.class)
public class GeneratorTest {


@Test
public void generatorEndPoint() {
when().get("https://bal-bla-bla-bla.com/generators")
.then().statusCode(SC_OK);
}
}

在我的例子中,简单的补丁是添加‘ useRelaxedHTTPSValidations ()’

RestAssured.useRelaxedHTTPSValidation();

那么测试看起来

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


import static com.jayway.restassured.RestAssured.when;
import static org.apache.http.HttpStatus.SC_OK;


@RunWith(SpringJUnit4ClassRunner.class)
public class GeneratorTest {


@Before
public void setUp() {
RestAssured.useRelaxedHTTPSValidation();
}




@Test
public void generatorEndPoint() {
when().get("https://bal-bla-bla-bla.com/generators")
.then().statusCode(SC_OK);
}
}

如果您正在使用 CloudFoundry,那么您必须显式地将 jar 与拥有证书的密钥存储区一起推送。

如果问题是缺少中间证书,您可以启用 Oracle JRE 自动下载缺少的中间证书,如 这个答案中所解释的。

只需设置 Java 系统属性 -Dcom.sun.security.enableAIAcaIssuers=true

为此,服务器的证书必须为中间证书(证书的颁发者)提供 URI。据我所知,浏览器也是这样做的,应该同样安全——尽管我不是一个安全专家。

编辑: 如果我没记错的话,这至少在 Java8中是可行的,而且是 在这里为 Java9编写了文档

我也面临这个问题。我有 JDK 1.8.0_121。我升级 JDK 到 1.8.0_181,它像一个魅力。

我也遇到了同样的问题。我试图以 clean install为目标来建立这个项目。我只是在运行配置中将其更改为 clean package -o。然后我重建了这个项目,它对我起作用了。

在 ApacheTomcat/7.0.67和 JavaJVM Version: 1.8.0 _ 66-b18上也有同样的问题。只要升级到 JRE 1.8.0 _ 241,问题似乎就解决了。