Wie löse ich den Fehler javax.net.ssl.SSLHandshakeException?

101

Ich habe mich mit VPN verbunden, um die Inventar-API einzurichten, um die Produktliste zu erhalten, und es funktioniert einwandfrei. Sobald ich das Ergebnis vom Web-Service bekomme und mich an die Benutzeroberfläche binde. Außerdem habe ich PayPal in meine Anwendung für die Express-Kaufabwicklung integriert, wenn ich einen Zahlungsaufruf tätige, bei dem dieser Fehler auftritt. Ich benutze Servlet für den Back-End-Prozess. Kann jemand sagen, wie man dieses Problem behebt?

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
selladurai
quelle
1
Was ich gerne wissen würde, welches genaue Ziel in diesem Fall war ... Sie erhalten eine Ausnahme, aber Sie erhalten keine Informationen über das Ziel, die sich möglicherweise von Ihren Erwartungen unterscheiden. Ich habe einen solchen Fall, ich bin sicher, mein Link hat Zertifikat, und ich
bekomme

Antworten:

151

Zunächst müssen Sie das öffentliche Zertifikat von dem Server erhalten, zu dem Sie eine Verbindung herstellen möchten. Dies kann auf verschiedene Arten geschehen, z. B. indem Sie den Serveradministrator kontaktieren und danach fragen, OpenSSL zum Herunterladen verwenden oder, da dies ein HTTP-Server zu sein scheint, eine Verbindung mit einem beliebigen Browser herstellen und die Sicherheitsinformationen der Seite anzeigen und Speichern einer Kopie des Zertifikats. (Google sollte Ihnen genau sagen können, was Sie für Ihren bestimmten Browser tun sollen.)

Nachdem Sie das Zertifikat in einer Datei gespeichert haben, müssen Sie es dem Trust Store Ihrer JVM hinzufügen. Bei $JAVA_HOME/jre/lib/security/für JREs oder $JAVA_HOME/lib/securityfür JDKs, gibt es eine Datei mit dem Namen cacerts, der mit Java kommt und enthält die öffentlichen Zertifikate der bekannten Zertifizierungsstellen. Führen Sie zum Importieren des neuen Zertifikats keytool als Benutzer aus, der zum Schreiben in cacerts berechtigt ist:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

Sie werden höchstwahrscheinlich nach einem Passwort gefragt. Das mit Java gelieferte Standardkennwort lautet changeit. Fast niemand ändert es. Nachdem Sie diese relativ einfachen Schritte ausgeführt haben, kommunizieren Sie sicher und mit der Gewissheit, dass Sie mit dem richtigen Server und nur mit dem richtigen Server sprechen (solange diese ihren privaten Schlüssel nicht verlieren).

Ryan Stewart
quelle
12
Ich brauche etwas mehr Details als "nicht funktionieren". Aktualisieren Sie Ihre Frage mit dem, was Sie versucht haben, und einer Fehlerausgabe. Leider ist es weit nach meiner Schlafenszeit, sodass vielleicht jemand anderes Ihre Fragen beantworten kann. Dies ist auch eine sehr häufige Situation. Sie können viele Informationen online finden, einschließlich der Keytool-Dokumente .
Ryan Stewart
Grundsätzlich muss ich PayPal-Zertifikat enthalten. Ich habe deine Schritte gemacht und das Zertifikat auch an der entsprechenden Stelle hinzugefügt. dann starte ich die App es sagt der gleiche Fehler?
Selladurai
Eigentlich funktioniert es gut, kein Problem Browser und ich habe VPN verbunden, um eine Inventarliste zu erhalten. Zu diesem Zeitpunkt bezahle ich mit PayPal. Es heißt SSL-Fehler, aber ich verwende Offline-Daten oder Hot-Coded-Daten, was bedeutet, dass es funktioniert.
Selladurai
4
@selladurai: Sie sollten kein Zertifikat für Paypal importieren müssen. Sofern Ihre cacerts-Datei nicht beschädigt oder geändert wurde, sollte sie alle vertrauenswürdigen Stammzertifikate enthalten, und das Paypal-Zertifikat sollte auf eines dieser Zertifikate zurückgeführt werden können. Sie könnten versuchen, eine Kopie von Cacerts zu erhalten, von denen Sie wissen, dass sie gut ist, und stattdessen diese versuchen. Wenn das Problem weiterhin besteht, stellen Sie möglicherweise keine Verbindung zu Paypal her.
Ryan Stewart
@ RyanStewart muss ich es irgendwie in Glassfish importieren? Da ich die CER-Datei zu meinem Cacert in meinem Java-Ausgangsverzeichnis hinzugefügt habe, Glassfish sie jedoch nicht zu verwenden scheint, wird immer noch der Fehler angezeigt.
Ced
15

Jetzt habe ich dieses Problem auf diese Weise gelöst,

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream; 

// Create a trust manager that does not validate certificate chains like the default 

TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
        }
};

// Install the all-trusting trust manager
try 
{
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} 
catch (Exception e) 
{
    System.out.println(e);
}

Natürlich sollte diese Lösung nur in Szenarien verwendet werden, in denen es nicht möglich ist, die erforderlichen Zertifikate mithilfe keytoollokaler Tests mit temporären Zertifikaten zu installieren .

selladurai
quelle
52
Wow, ich würde zögern, das als "Fix" zu bezeichnen. Sie haben im Grunde nur die Sicherheit ausgeschaltet. Ja, die Daten werden weiterhin verschlüsselt, aber Sie können nicht garantieren, dass Sie mit dem sprechen, mit dem Sie voraussichtlich sprechen werden. Die richtige Lösung besteht darin, den öffentlichen Schlüssel Ihres Zielservers abzurufen und in den Trust Store der JVM zu importieren, die die Verbindung herstellt.
Ryan Stewart
1
siehe meine Antwort für eine geeignete Lösung
Ryan Stewart
Beispiel für was? Meine Antwort sollte alle Schritte enthalten, die Sie benötigen.
Ryan Stewart
3
Der hier gezeigte Code sieht hilfreich aus, wenn Sie einen sehr einfachen Test gegen einen Entwicklungsserver schreiben. Ich würde mich jedoch nicht auf ihn für die Produktion verlassen.
Jason D
12

Wann immer wir versuchen, eine Verbindung zur URL herzustellen,

Wenn der Server am anderen Standort mit dem https-Protokoll ausgeführt wird und die Kommunikation über die im Zertifikat angegebenen Informationen vorschreibt, haben wir folgende Option:

1) Fordern Sie das Zertifikat an (laden Sie das Zertifikat herunter) und importieren Sie dieses Zertifikat in Trustore. Die standardmäßigen Java-Verwendungen von Trustore finden Sie unter \ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacerts. Wenn wir erneut versuchen, eine Verbindung zur URL-Verbindung herzustellen, wird dies akzeptiert.

2) In normalen Geschäftsfällen stellen wir möglicherweise eine Verbindung zu internen URLs in Organisationen her und wissen, dass diese korrekt sind. In solchen Fällen vertrauen Sie darauf, dass es sich um die richtige URL handelt. In den oben genannten Fällen kann Code verwendet werden, der nicht das Speichern des Zertifikats für die Verbindung mit einer bestimmten URL vorschreibt.

Für den Punkt Nr. 2 müssen wir die folgenden Schritte ausführen:

1) Schreiben Sie die folgende Methode, mit der HostnameVerifier für HttpsURLConnection festgelegt wird, die in allen Fällen true zurückgibt, was bedeutet, dass wir dem trustStore vertrauen.

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) Schreiben Sie die folgende Methode, die doTrustToCertificates aufruft, bevor Sie versuchen, eine Verbindung zur URL herzustellen

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

Dieser Aufruf gibt den Antwortcode = 200 zurück, was bedeutet, dass die Verbindung erfolgreich ist.

Weitere Einzelheiten und ein Beispiel finden Sie unter URL .

Shirishkumar Bari
quelle
1
Der Google Play Store wird dies ablehnen. Sie werden sehen, dass Sie das X509-Zertifikat während des APK-Scans ignorieren.
Oliver Dixon
0

Ich glaube, dass Sie versuchen, über SSL eine Verbindung zu etwas herzustellen, aber dass etwas ein Zertifikat bereitstellt, das nicht von Root-Zertifizierungsstellen wie verisign überprüft wurde. Im Wesentlichen können sichere Verbindungen standardmäßig nur hergestellt werden, wenn die Person, die versucht, eine Verbindung herzustellen, dies weiß Die Schlüssel der Gegenparteien oder eine andere Verndor wie Verisign können eingreifen und sagen, dass der bereitgestellte öffentliche Schlüssel tatsächlich richtig ist.

ALLE Betriebssysteme vertrauen darauf, dass eine Handvoll Zertifizierungsstellen und kleinere Zertifikatsaussteller von einem der großen Zertifizierer zertifiziert werden müssen, die eine Kette von Zertifizierern bilden, wenn Sie verstehen, was ich meine ...

Wie auch immer, ich komme auf den Punkt zurück. Ich hatte ein ähnliches Problem beim Programmieren eines Java-Applets und eines Java-Servers (Hoffentlich schreibe ich eines Tages einen vollständigen Blogpost darüber, wie ich die gesamte Sicherheit zum Laufen gebracht habe :))

Im Wesentlichen musste ich die öffentlichen Schlüssel vom Server extrahieren und in einem Schlüsselspeicher in meinem Applet speichern. Als ich eine Verbindung zum Server herstellte, verwendete ich diesen Schlüsselspeicher, um eine Vertrauensfactory zu erstellen, und diese Vertrauensfabrik, um die SSL zu erstellen Verbindung. Es gibt auch alternative Verfahren wie das Hinzufügen des Schlüssels zum vertrauenswürdigen Host der JVM und das Ändern des Standard-Vertrauensspeichers beim Start.

Ich habe dies vor ungefähr zwei Monaten getan und habe momentan keinen Quellcode bei mir. Verwenden Sie Google und Sie sollten in der Lage sein, dieses Problem zu lösen. Wenn Sie mir keine Nachricht senden können und ich Ihnen den relevanten Quellcode für das Projekt zur Verfügung stellen kann, wissen Sie nicht, ob dies Ihr Problem löst, da Sie den Code, der diese Ausnahmen verursacht, nicht angegeben haben. Außerdem habe ich mit Applets gearbeitet, von denen ich dachte, ich kann nicht verstehen, warum es auf Serverlets nicht funktioniert ...

PS Ich kann vor dem Wochenende keinen Quellcode erhalten, da externes SSH in meinem Büro deaktiviert ist :(

Osama Javed
quelle
1
PS Ich habe diesen Java-Code online gefunden, um die öffentlichen Schlüssel meines Servers zu extrahieren und zu speichern. Also googeln Sie weiter oder warten Sie bis Sonntag
Osama Javed
0

SSLHandshakeException kann auf zwei Arten gelöst werden.

  1. Einbindung von SSL

    • Holen Sie sich das SSL (indem Sie den Administrator des Quellsystems fragen, kann es auch mit dem Befehl openssl heruntergeladen werden oder jeder Browser lädt die Zertifikate herunter)

    • Fügen Sie das Zertifikat in den Truststore (cacerts) unter JRE / lib / security ein

    • Geben Sie den Truststore-Speicherort in VM-Argumenten als "-Djavax.net.ssl.trustStore =" an.

  2. SSL ignorieren

    Besuchen Sie für diese Nummer 2 meine andere Antwort auf einer anderen Stackoverflow-Website: So führen Sie eine SSL-Überprüfung durch Ignorieren von SSL-Zertifikatfehlern mit Java

Amit Kaneria
quelle
-8

Jetzt habe ich dieses Problem auf diese Weise gelöst,

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream;
// Create a trust manager that does not validate certificate chains like the 
default TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
    }
};
// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
    System.out.println(e);
}
Evelyn Condes
quelle
4
"Keine Notwendigkeit zu implementieren" ist völlig und völlig falsch. Sie haben gerade Ihre SSL-Verbindung unsicher gemacht. Tu das nicht.
Marquis von Lorne