Das Ignorieren der PKIX-Pfaderstellung ist fehlgeschlagen: sun.security.provider.certpath.SunCertPathBuilderException?

73

Beim Versuch, eine Anfrage an einen http-Server zu senden, wurde die folgende Ausnahme angezeigt:

Hier ist der Code, den ich verwendet habe

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 ist die Ausnahme:

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

Der Server gehört mir nicht. Gibt es eine Möglichkeit, diese Ausnahme zu ignorieren?

DeepNightTwo
quelle
5
Sie nicht ignorieren diese Ausnahme. Importieren Sie das Zertifikat (nach einer manuellen Überprüfung) in Ihren Trust Store. Durch das Ignorieren von Zertifikatfehlern wird die Verbindung für potenzielle MITM-Angriffe anfällig.
Bruno
12
Es gibt Zeiten, in denen Vertrauen für den Client nicht wichtig ist, https jedoch vom Server verwendet wurde.
Gus
Ich bekomme diesen Fehler nur manchmal - mit demselben Server. Wenn Sie es eine Sekunde später erneut versuchen, wird die Anforderung ausgeführt. Der Server ist botcompany.de und verfügt über ein LetsEncrypt-Zertifikat. Wie kann das erklärt werden? Hatte noch nie dieses Problem mit einem Comodo-Zertifikat. Keine Ahnung, ob das Zertifikat der Grund ist. Auf dem Server wird NanoHTTPD ausgeführt.
Stefan Reich

Antworten:

53

Wenn Sie das Zertifikat insgesamt ignorieren möchten, sehen Sie sich die Antwort hier an: Ignorieren Sie das selbstsignierte SSL-Zertifikat mit Jersey Client

Dies macht Ihre App jedoch anfällig für Man-in-the-Middle-Angriffe.

Oder versuchen Sie, das Zertifikat als vertrauenswürdiges Zertifikat zu Ihrem Java-Speicher hinzuzufügen. Diese Seite kann hilfreich sein. http://blog.icodejava.com/tag/get-public-key-of-ssl-certificate-in-java/

Hier ist ein weiterer Thread, der zeigt, wie Sie Ihrem Geschäft ein Zertifikat hinzufügen. Java SSL-Verbindung, Serverzertifikat programmgesteuert zum Keystore hinzufügen

Der Schlüssel ist:

KeyStore.Entry newEntry = new KeyStore.TrustedCertificateEntry(someCert);
ks.setEntry("someAlias", newEntry, null);
km1
quelle
Diese Lösung hat bei mir funktioniert
Radu Linu
44

Ich habe den folgenden Code verwendet, um die SSL-Prüfung in meinem Projekt zu überschreiben, und es hat bei mir funktioniert.

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);
        }
    }
}
Kishore Kumar
quelle
Befolgen Sie nicht den Vertrag.
Marquis von Lorne
In Ihrem Aufruf an sc.init()kann das dritte Argument sein null. (Ein Standardwert wird angegeben.)
Kevinarpe
1
Dank dieses Fixes werden alle ungültigen Zertifikate ignoriert. Dies ist sehr nützlich, wenn das Zertifikat alle 3 Monate automatisch erneuert wird, z. B. die Let's Encrypt-Zertifikate, und Sie das Zertifikat nicht wirklich alle 3 Monate manuell im Java Trust Store installieren können ...
fnicollet
Das funktioniert nur für HTTP, oder? Aber nicht SMTP. Ich habe dies mit SMTP getestet, nichts getan (immer noch die gleichen Zertifizierungsfehler ... bis ich das Zertifikat schließlich zum Keystore hinzufügte).
KajMagnus
19

Setzen Sie die validateTLSCertificatesEigenschaft falsefür Ihren JSoup- Befehl auf.

Jsoup.connect("https://google.com/").validateTLSCertificates(false).get();
Zahid Hasan
quelle
5

FWIW, unter Ubuntu 10.04.2 LTS hat die Installation der Pakete ca-certificates-java und ca-certificates dieses Problem für mich behoben.

schlank
quelle
Omg nach 6 Stunden Kampf mit meiner alten Ubuntu 10.04 VM, dies behebt diesen lästigen Fehler. Diese Version ist so alt, dass ich source.list
jpp1jpp1
3

Ich habe den gleichen Fehler beim Ausführen des folgenden einfachen Spring-Boot + RestAssured-Tests erhalten.

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

Die einfache Lösung in meinem Fall ist das Hinzufügen von 'useRelaxedHTTPSValidations ()'.

RestAssured.useRelaxedHTTPSValidation();

Dann sieht der Test so aus

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);
    }
}
Praveen
quelle
2

Wenn es sich um ein fehlendes Zwischenzertifikat handelt, können Sie Oracle JRE aktivieren, um das fehlende Zwischenzertifikat automatisch herunterzuladen, wie in dieser Antwort erläutert .

Legen Sie einfach die Java-Systemeigenschaft fest -Dcom.sun.security.enableAIAcaIssuers=true

Damit dies funktioniert, muss das Serverzertifikat den URI für das Zwischenzertifikat (den Aussteller des Zertifikats) bereitstellen. Soweit ich das beurteilen kann, tun dies auch Browser und sollten genauso sicher sein - ich bin jedoch kein Sicherheitsexperte.

Bearbeiten: Wenn ich mich richtig erinnere, scheint dies zumindest mit Java 8 zu funktionieren und ist hier für Java 9 dokumentiert .

Ben Romberg
quelle
Sie sollten angeben, auf welcher Java-Version Ihre Lösung funktioniert. Versuchte es und es funktioniert nicht mit JDK 1.7.0_13
Rafael Palomino
1

Wenn Sie CloudFoundry verwenden, müssen Sie das JAR explizit zusammen mit dem Keystore mit dem Zertifikat verschieben.

Smart Coder
quelle
0

Ich habe mich auch diesem Problem gestellt. Ich hatte JDK 1.8.0_121. Ich habe JDK auf aktualisiert 1.8.0_181und es hat wie ein Zauber funktioniert.

Osanda Deshan
quelle