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


74

尝试将请求发布到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

该服务器不属于我。有没有办法忽略此异常?


5
不要忽略此异常。将证书(经过一些手动验证)导入信任库中。忽略证书错误会使连接容易受到潜在的MITM攻击。
布鲁诺

12
有时候信任对客户端并不重要,但是服务器仍然使用https。
2014年

我只有在同一台服务器上有时才收到此错误。一秒钟后再试一次,请求通过。服务器为botcompany.de,并具有LetsEncrypt证书。如何解释呢?Comodo证书从未出现过此问题。不知道证书是否是原因。服务器正在运行NanoHTTPD。
Stefan Reich

Answers:


54

如果您想一起忽略证书,请在此处查看答案:使用Jersey客户端忽略自签名的ssl证书

尽管这会使您的应用容易受到中间人攻击。

或者,尝试将证书作为受信任的证书添加到Java存储中。该站点可能会有所帮助。 http://blog.icodejava.com/tag/get-public-key-of-ssl-certificate-in-java/

这是另一个线程,显示如何向您的商店添加证书。 Java SSL连接,以编程方式将服务器证书添加到密钥库

关键是:

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

这个解决方案对我
有用

这是someCert什么 我应该如何创建它?
伊莱·哈里奇

45

我已使用以下代码覆盖了项目中的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);
        }
    }
}

不遵守合同。
user207421 '16

在您致电时sc.init(),第三个参数可能是null。(将提供默认值。)
kevinarpe

1
谢谢,此修复程序将忽略所有无效证书。当证书每3个月自动更新一次(例如让我们加密证书),并且您不能真正每3个月在Java信任库中手动安装证书时,这
很有用

这仅适用于HTTP,对吧?但不是SMTP。我使用SMTP测试了此操作,却没有做任何事情(仍然出现相同的证书错误……直到最终将证书添加到密钥库中)。
KajMagnus



3

我在执行下面的spring-boot + RestAssured简单测试时遇到了相同的错误。

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);
    }
}

2

如果问题是缺少中间证书,则可以按照此答案中的说明使Oracle JRE自动下载缺少的中间证书。

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

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

编辑:如果我没记错的话,这似乎至少与Java 8兼容,并在此处针对Java 9进行了说明


您应该提及您的解决方案适用于哪个Java版本。试过了,它不能与JDK 1.7.0_13一起使用
Rafael Palomino

1

如果您使用的是CloudFoundry,则必须显式地将jar和具有证书的密钥库一起推送。


0

我也面临这个问题。我有JDK 1.8.0_121。我将JDK升级到1.8.0_181,并且像魅力一样工作。


0

我也遇到过同样的问题。我试图以一个clean install目标来构建项目。我只是将其更改clean package -o为运行配置。然后,我重新构建了该项目,它为我工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.