628 Stimmen

Auflösen von javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX-Pfaderstellung fehlgeschlagen Fehler?

Bearbeiten: Ich habe versucht, die Frage und die akzeptierte Antwort in einer vorzeigbareren Form in meinem Blog .

Hier ist die Originalausgabe.

Ich erhalte diesen Fehler:

Ausführliche Meldung sun.security.validator.ValidatorException: PKIX-Pfad Erstellung fehlgeschlagen:
sun.security.provider.certpath.SunCertPathBuilderException: kann nicht auf keinen gültigen Zertifizierungspfad zum angeforderten Ziel finden

javax.net.ssl.SSLHandshakeException verursachen: sun.security.validator.ValidatorException: PKIX-Pfaderstellung fehlgeschlagen: sun.security.provider.certpath.SunCertPathBuilderException: Unfähig, einen gültigen Zertifizierungspfad für das angeforderte Ziel zu finden

Ich verwende Tomcat 6 als Webserver. Ich habe zwei HTTPS-Webanwendungen auf verschiedenen Tomcats an verschiedenen Ports, aber auf demselben Rechner installiert. Sagen wir App1 (Port 8443) und App2 (Port 443). App1 stellt eine Verbindung zu App2 her. Wenn App1 eine Verbindung zu App2 herstellt, erhalte ich den oben genannten Fehler. Ich weiß, dass dieser Fehler sehr häufig auftritt, und habe in verschiedenen Foren und auf verschiedenen Websites viele Lösungen gefunden. Ich habe den folgenden Eintrag in server.xml der beiden Tomcats:

keystoreFile="c:/.keystore" 
keystorePass="changeit"

Auf jeder Website wird derselbe Grund angegeben: Das von app2 ausgestellte Zertifikat befindet sich nicht im vertrauenswürdigen Speicher von app1 jvm. Dies scheint auch dann zuzutreffen, wenn ich versuche, die gleiche URL im IE-Browser aufzurufen, was auch funktioniert (mit der Meldung Es gibt ein Problem mit dem Sicherheitszertifikat dieser Website. Hier sage ich weiter zu dieser Website). Aber wenn dieselbe URL von einem Java-Client aufgerufen wird (in meinem Fall), erhalte ich den oben genannten Fehler. Um sie in den Truststore aufzunehmen, habe ich diese drei Optionen ausprobiert:

Option 1

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

Option 2

Folgende Einstellung in der Umgebungsvariable

CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

Option 3

Folgende Einstellung in der Umgebungsvariable

JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

Ergebnis

Aber nichts funktionierte.

Was endlich funktionierte führt den Java-Ansatz aus, der in Wie behandelt man ungültige SSL-Zertifikate mit Apache HttpClient? von Pascal Thivent, d.h. die Ausführung des Programms InstallCert.

Aber dieser Ansatz ist gut für Devbox-Setup, aber ich kann es nicht in der Produktionsumgebung verwenden.

Ich frage mich, warum die drei oben genannten Ansätze nicht funktionieren, wenn ich die gleichen Werte in server.xml des App2-Servers und dieselben Werte im Truststore durch Setzen von

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

im Programm App1.

Für weitere Informationen stelle ich die Verbindung folgendermaßen her:

URL url = new URL(urlStr);

URLConnection conn = url.openConnection();

if (conn instanceof HttpsURLConnection) {

  HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();

  conn1.setHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
      return true;
    }
  });

  reply.load(conn1.getInputStream());

548voto

SimonSez Punkte 7159

Sie müssen das Zertifikat hinzufügen für App2 in die Truststore-Datei des verwendeten JVM gelegen bei $JAVA_HOME\lib\security\cacerts .

Zunächst können Sie überprüfen, ob Ihr Zertifikat bereits im Truststore vorhanden ist, indem Sie den folgenden Befehl ausführen: keytool -list -keystore "$JAVA_HOME/jre/lib/security/cacerts" (Sie brauchen kein Passwort anzugeben)

Wenn Ihr Zertifikat fehlt, können Sie es mit Ihrem Browser herunterladen und mit dem folgenden Befehl zum Truststore hinzufügen:

keytool -import -noprompt -trustcacerts -alias <AliasName> -file   <certificate> -keystore <KeystoreFile> -storepass <Password>

Exemple :

keytool -import -noprompt -trustcacerts -alias myFancyAlias -file /path/to/my/cert/myCert.cer -keystore /path/to/my/jdk/jre/lib/security/cacerts/keystore.jks -storepass changeit

Nach dem Import können Sie den ersten Befehl erneut ausführen, um zu überprüfen, ob Ihr Zertifikat hinzugefügt wurde.

Informationen zu Sun/Oracle finden Sie unter aquí .

243voto

NDeveloper Punkte 3025

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX-Pfaderstellung fehlgeschlagen: sun.security.provider.certpath.SunCertPathBuilderException: Es konnte kein gültiger Zertifizierungspfad zum angeforderten Ziel gefunden werden

- Als ich die Fehlermeldung erhielt, versuchte ich, die Bedeutung des Ausdrucks zu googeln und fand heraus, dass dieses Problem auftritt, wenn ein Server sein HTTPS-SSL-Zertifikat ändert und unsere ältere Version von Java die Root-Zertifizierungsstelle (CA) nicht erkennt.

- Wenn Sie in Ihrem Browser auf die HTTPS-URL zugreifen können, ist es möglich, Java zu aktualisieren, um die Root-CA zu erkennen.

- Rufen Sie in Ihrem Browser die HTTPS-URL auf, auf die Java nicht zugreifen konnte. Klicken Sie auf die HTTPS-Zertifikatskette (im Internet Explorer gibt es ein Schlosssymbol), klicken Sie auf das Schloss, um das Zertifikat anzuzeigen.

- Gehen Sie zu "Details" des Zertifikats und "In Datei kopieren". Kopieren Sie es in Base64 (.cer) Format. Es wird auf Ihrem Desktop gespeichert.

- Installieren Sie das Zertifikat und ignorieren Sie dabei alle Warnungen.

- So habe ich die Zertifikatsinformationen der URL gesammelt, auf die ich zugreifen wollte.

Nun musste ich meine Java-Version so einstellen, dass sie von dem Zertifikat weiß, damit sie sich nicht weigert, die URL zu erkennen. In diesem Zusammenhang muss ich erwähnen, dass ich gegoogelt habe, dass Root-Zertifikat-Informationen standardmäßig in JDK's \jre\lib\security und das Standard-Passwort für den Zugang ist: ändern.

Um die Cacerts-Informationen anzuzeigen, gehen Sie wie folgt vor:

- Klicken Sie auf die Schaltfläche Start-->Ausführen

- Geben Sie cmd ein. Die Eingabeaufforderung wird geöffnet (möglicherweise müssen Sie sie als Administrator öffnen).

- Gehen Sie zu Ihrem Java/jreX/bin Verzeichnis

- Geben Sie Folgendes ein

keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts

Sie zeigt eine Liste der aktuellen Zertifikate im Keystore an. Sie sieht in etwa so aus:

C:\Documents and Settings\NeelanjanaG>keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts

Enter keystore password:  changeit

Keystore type: jks

Keystore provider: SUN

Your keystore contains 44 entries

verisignclass3g2ca, Mar 26, 2004, trustedCertEntry,

Certificate fingerprint (MD5): A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9

entrustclientca, Jan 9, 2003, trustedCertEntry,

Certificate fingerprint (MD5): 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4

thawtepersonalbasicca, Feb 13, 1999, trustedCertEntry,

Certificate fingerprint (MD5): E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41

addtrustclass1ca, May 1, 2006, trustedCertEntry,

Certificate fingerprint (MD5): 1E:42:95:02:33:92:6B:B9:5F:C0:7F:DA:D6:B2:4B:FC

verisignclass2g3ca, Mar 26, 2004, trustedCertEntry,

Certificate fingerprint (MD5): F8:BE:C4:63:22:C9:A8:46:74:8B:B8:1D:1E:4A:2B:F6

- Nun musste ich das zuvor installierte Zertifikat in die cacerts aufnehmen.

- Dabei wird wie folgt vorgegangen:

keytool -import -noprompt -trustcacerts -alias ALIASNAME -file FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD

Wenn Sie Java 7 verwenden:

keytool -importcert -trustcacerts -alias ALIASNAME -file PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit

- Es fügt dann die Zertifikatsinformationen in die Datei cacert ein.

Das ist die Lösung, die ich für die oben erwähnte Ausnahme gefunden habe!!

63voto

So funktioniert es in Tomcat 7

Ich wollte ein selbstsigniertes Zertifikat in einer Tomcat-App unterstützen, aber das folgende Snippet funktioniert nicht

import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HTTPSPlayground {
    public static void main(String[] args) throws Exception {

        URL url = new URL("https:// ... .com");
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        httpURLConnection.setDoOutput(true);
        DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());

        String serializedMessage = "{}";
        wr.writeBytes(serializedMessage);
        wr.flush();
        wr.close();

        int responseCode = httpURLConnection.getResponseCode();
        System.out.println(responseCode);
    }
}

Das hat mein Problem gelöst:

1) Laden Sie die .crt Datei

echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
  • ersetzen. <your domain> mit Ihrer Domäne (z.B. jossef.com )

2) Wenden Sie die .crt Datei in Javas cacerts Zertifikatsspeicher

keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <JAVA HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
  • ersetzen. <your domain> mit Ihrer Domäne (z.B. jossef.com )
  • ersetzen. <JAVA HOME> mit Ihrem Java-Home-Verzeichnis

3) Hacken Sie es

Auch wenn ich mein Zertifikat in Java Standard-Zertifikatspeicher, Tomcat ignoriert das (anscheinend ist es nicht so konfiguriert, dass es die Standard-Zertifikatspeicher von Java verwendet).

Um dies zu umgehen, fügen Sie Folgendes in Ihren Code ein:

String certificatesTrustStorePath = "<JAVA HOME>/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);

// ...

25voto

Guillaume Punkte 13867

In meinem Fall bestand das Problem darin, dass der Webserver nur das Zertifikat und die Zwischenzertifizierungsstelle, nicht aber die Stammzertifizierungsstelle übermittelte. Durch Hinzufügen dieser JVM-Option wurde das Problem gelöst: -Dcom.sun.security.enableAIAcaIssuers=true

Unterstützung für die Zugriffsmethode caIssuers der Erweiterung Authority Information Access ist verfügbar. Sie ist aus Kompatibilitätsgründen standardmäßig deaktiviert und kann durch Setzen der Systemeigenschaft com.sun.security.enableAIAcaIssuers auf den Wert true.

Wenn diese Option auf true gesetzt ist, verwendet die PKIX-Implementierung von CertPathBuilder von Sun die Informationen in der AIA-Erweiterung eines Zertifikats (zusätzlich zu den angegebenen CertStores), um das ausstellende CA-Zertifikat zu finden, sofern es sich um eine URI des Typs ldap, http oder ftp handelt.

Quelle

13voto

Sandip S. Punkte 600

Es ist möglich, die SSL-Verifizierung programmatisch zu deaktivieren. Das funktioniert in der Not für Entwickler, wird aber für die Produktion nicht empfohlen, da Sie dort entweder die "echte" SSL-Verifizierung verwenden oder Ihre eigenen vertrauenswürdigen Schlüssel installieren und verwenden und dann immer noch die "echte" SSL-Verifizierung verwenden möchten.

Der unten stehende Code funktioniert bei mir:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class TrustAnyTrustManager implements X509TrustManager {

  public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  }

  public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  }

  public X509Certificate[] getAcceptedIssuers() {
    return null;
  }
}

             HttpsURLConnection conn = null;
             URL url = new URL(serviceUrl);
             conn = (HttpsURLConnection) url.openConnection();
             SSLContext sc = SSLContext.getInstance("SSL");  
             sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());  
                    // Create all-trusting host name verifier
             HostnameVerifier allHostsValid = new HostnameVerifier() {
               public boolean verify(String hostname, SSLSession session) {
                return true;
              }
            };
            conn.setHostnameVerifier(allHostsValid);

Oder wenn Sie nicht die Kontrolle über die Connection können Sie die SSL-Überprüfung auch global für alle Verbindungen außer Kraft setzen https://stackoverflow.com/a/19542614/32453

Wenn Sie den Apache HTTPClient verwenden, müssen Sie ihn "anders" deaktivieren (leider): https://stackoverflow.com/a/2703233/32453

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X