Hoe PKIX Path Building te negeren mislukt: sun.security.provider.certpath.suncertpathbuilderexception?

Ik heb de volgende uitzondering bij het proberen om een ​​verzoek naar een HTTP-server te plaatsen:

Hier is de code die ik gebruikte

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

Hier is de uitzondering:

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

De server is niet eigendom van mij. Is er een manier om deze uitzondering te negeren?


Antwoord 1, Autoriteit 100%

Als je het certificaat helemaal wilt negeren, bekijk dan hier het antwoord: Negeer zelfondertekend SSL-certificaat met Jersey Client

Hoewel dit je app kwetsbaar maakt voor man-in-the-middle-aanvallen.

Of probeer het certificaat aan uw Java-winkel toe te voegen als een vertrouwd certificaat.
Deze site kan nuttig zijn.
http://blog.icodejava.com/ tag/get-public-key-of-ssl-certificate-in-java/

Hier is nog een thread die laat zien hoe u een certificaat aan uw winkel kunt toevoegen.
Java SSL-verbinding, servercertificaat programmatisch aan keystore toevoegen

De sleutel is:

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

Antwoord 2, autoriteit 100%

Ik heb de onderstaande code gebruikt om de SSL-controle in mijn project te negeren en het werkte voor mij.

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

Antwoord 3, autoriteit 36%

Stel de eigenschap validateTLSCertificatesin op falsevoor uw JSoup-opdracht.

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

Antwoord 4, autoriteit 11%

FWIW, op Ubuntu 10.04.2 LTS heeft het installeren van de ca-certificates-java en de ca-certificates-pakketten dit probleem voor mij opgelost.


Antwoord 5, autoriteit 9%

Ik kreeg dezelfde fout tijdens het uitvoeren van de onderstaande spring-boot + RestAssured eenvoudige test.

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

De eenvoudige oplossing in mijn geval is om ‘useRelaxedHTTPSValidations()’ toe te voegen

RestAssured.useRelaxedHTTPSValidation();

De test ziet er dan uit als

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

Antwoord 6, autoriteit 9%

Als het probleem een ​​ontbrekend tussencertificaat is, kunt u Oracle JRE inschakelen om het ontbrekende tussencertificaat automatisch te downloaden, zoals uitgelegd in dit antwoord.

Stel gewoon de Java-systeemeigenschap -Dcom.sun.security.enableAIAcaIssuers=true

in

Om dit te laten werken, moet het certificaat van de server de URI naar het tussenliggende certificaat (de uitgever van het certificaat) verstrekken. Voor zover ik weet, is dit wat browsers ook doen en net zo veilig zouden moeten zijn – ik ben echter geen beveiligingsexpert.

Bewerken: als ik het me goed herinner, lijkt dit in ieder geval te werken met Java 8 en is het hier gedocumenteerd voor Java 9.


Antwoord 7, autoriteit 4%

Als je CloudFoundry gebruikt, moet je de jar expliciet samen met de keystore met het certificaat pushen.


Antwoord 8, autoriteit 2%

Ik kwam hetzelfde probleem ook tegen. Ik probeerde het project te bouwen met een clean installdoel. Ik heb het gewoon veranderd in clean package -oin de run-configuratie. Daarna heb ik het project opnieuw opgebouwd en het werkte voor mij.


Antwoord 9

Ik heb ook met dit probleem te maken gehad. Ik had JDK 1.8.0_121. Ik heb JDK geüpgraded naar 1.8.0_181en het werkte als een tierelier.


Antwoord 10

Ik heb hetzelfde probleem met Apache Tomcat/7.0.67 en Java JVM-versie: 1.8.0_66-b18. Net geüpgraded naar JRE 1.8.0_241, het lijkt erop dat het probleem is opgelost.

Other episodes