Akzeptieren Sie das selbstsignierte SSL-Zertifikat des Servers im Java-Client

Lesezeit: 12 Minuten

Akzeptieren Sie das selbstsignierte SSL Zertifikat des Servers im Java Client
Nikita Rybak

Es sieht aus wie eine Standardfrage, aber ich konnte nirgendwo eine klare Anleitung finden.

Ich habe Java-Code, der versucht, eine Verbindung zu einem Server mit wahrscheinlich selbstsigniertem (oder abgelaufenem) Zertifikat herzustellen. Der Code meldet folgenden Fehler:

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

Wie ich es verstehe, muss ich verwenden Schlüsselwerkzeug und teilen Sie Java mit, dass es in Ordnung ist, diese Verbindung zuzulassen.

Alle Anweisungen zur Behebung dieses Problems setzen voraus, dass ich mit Keytool, wie z

Generieren Sie einen privaten Schlüssel für den Server und importieren Sie ihn in den Schlüsselspeicher

Gibt es jemanden, der eine detaillierte Anleitung posten könnte?

Ich verwende Unix, also wäre Bash-Skript am besten.

Nicht sicher, ob es wichtig ist, aber in jboss ausgeführter Code.

  • Siehe Wie akzeptiere ich ein selbstsigniertes Zertifikat mit einer Java HttpsURLConnection?. Offensichtlich wäre es besser, wenn Sie die Site dazu bringen könnten, ein gültiges Zertifikat zu verwenden.

    – Matthäus Flaschen

    23. Mai 2010 um 22:52 Uhr


  • Danke für den Link, hatte ich beim Suchen nicht gefunden. Aber beide Lösungen beinhalten einen speziellen Code zum Senden einer Anfrage, und ich verwende vorhandenen Code (amazon ws client for java). Dementsprechend ist es ihre Site, die ich verbinde, und ich kann ihre Zertifikatsprobleme nicht beheben.

    – Nikita Rybak

    23. Mai 2010 um 23:22 Uhr

  • @MatthewFlaschen – “Natürlich wäre es besser, wenn Sie die Site dazu bringen könnten, ein gültiges Zertifikat zu verwenden …” – Ein selbstsigniertes Zertifikat ist ein gültiges Zertifikat, wenn der Client ihm vertraut. Viele halten es für einen Sicherheitsmangel, dem CA/Browser-Kartell Vertrauen zu schenken.

    – jww

    4. Juni 2017 um 8:12 Uhr


  • Verwandte, siehe Der gefährlichste Code der Welt: Validierung von SSL-Zertifikaten in Nicht-Browser-Software. (Der Link wird bereitgestellt, da Sie anscheinend diese Spam-Antworten erhalten, die die Validierung deaktivieren).

    – jww

    4. Juni 2017 um 9:42 Uhr

Akzeptieren Sie das selbstsignierte SSL Zertifikat des Servers im Java Client
Pascal Thivent

Sie haben hier grundsätzlich zwei Möglichkeiten: Fügen Sie das selbstsignierte Zertifikat zu Ihrem JVM-Truststore hinzu oder konfigurieren Sie Ihren Client so

Option 1

Exportieren Sie das Zertifikat aus Ihrem Browser und importieren Sie es in Ihren JVM-Truststore (um eine Vertrauenskette aufzubauen):

<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

Option 2

Zertifikatvalidierung deaktivieren:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {     
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        } 
        public void checkClientTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
            } 
        public void checkServerTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    } 
}; 

// 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 (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

Beachten Sie, dass Ich empfehle die Option #2 überhaupt nicht. Das Deaktivieren des Trust-Managers macht einige Teile von SSL unwirksam und macht Sie anfällig für Man-in-the-Middle-Angriffe. Bevorzugen Sie Option Nr. 1 oder, noch besser, lassen Sie den Server ein “echtes” Zertifikat verwenden, das von einer bekannten CA signiert ist.

  • Nicht nur der MIM-Angriff. Es macht Sie anfällig dafür, sich mit der falschen Seite zu verbinden. Es ist völlig unsicher. Siehe RFC 2246. Ich bin jederzeit dagegen, diesen TrustManager zu veröffentlichen. Es ist nicht einmal korrekt bzgl. seiner eigenen Spezifikation.

    – Benutzer207421

    24. Mai 2010 um 8:38 Uhr

  • @EJP Ich empfehle die zweite Option wirklich nicht (ich habe meine Antwort aktualisiert, um sie klarzustellen). Wenn Sie es jedoch nicht veröffentlichen, wird nichts gelöst (dies sind öffentliche Informationen) und verdient meiner Meinung nach keine Ablehnung.

    – Pascal Thivent

    24. Mai 2010 um 11:17 Uhr


  • @EJP Indem Sie die Menschen unterrichten, erziehen Sie sie, nicht indem Sie Dinge verstecken. Dinge geheim zu halten oder im Dunkeln zu halten, ist also überhaupt keine Lösung. Dieser Code ist öffentlich, die Java-API ist öffentlich, es ist besser, darüber zu sprechen, als ihn zu ignorieren. Aber ich kann damit leben, dass du nicht zustimmst.

    – Pascal Thivent

    25. Mai 2010 um 0:10 Uhr

  • Die andere Option – die Sie nicht erwähnen – ist zu Holen Sie sich das Zertifikat des Servers repariert entweder indem Sie es selbst beheben oder indem Sie die zuständigen Support-Mitarbeiter anrufen. Einzelhostzertifikate sind wirklich sehr billig; Herumfummeln mit selbst signiertem Zeug ist ein Cent-weise Pfund-Blödsinn (dh für diejenigen, die mit dieser englischen Redewendung nicht vertraut sind, eine völlig dumme Reihe von Prioritäten, die viel kosten, um fast nichts zu sparen).

    – Donal Fellows

    21. Juni 2011 um 7:59 Uhr

  • @Rich, 6 Jahre zu spät, aber Sie können das Serverzertifikat auch in Firefox abrufen, indem Sie auf das Schlosssymbol klicken -> weitere Informationen -> Zertifikat anzeigen -> Registerkarte Details -> Exportieren … Es ist gut versteckt.

    – Siddhartha

    6. April 2018 um 22:25 Uhr

1646578642 740 Akzeptieren Sie das selbstsignierte SSL Zertifikat des Servers im Java Client
Johannes Brodwall

Es gibt eine bessere Alternative, allen Zertifikaten zu vertrauen: Erstellen Sie a TrustStore die einem bestimmten Zertifikat ausdrücklich vertraut, und verwenden Sie dieses, um eine zu erstellen SSLContext von denen man die bekommt SSLSocketFactory auf die setzen HttpsURLConnection. Hier ist der vollständige Code:

File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
// Or if the crt-file is packaged into a jar file:
// CertificateFactory.getInstance("X.509").generateCertificate(this.class.getClassLoader().getResourceAsStream("server.crt"));


KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

Alternativ können Sie die laden KeyStore direkt aus einer Datei oder rufen Sie das X.509-Zertifikat von einer vertrauenswürdigen Quelle ab.

Beachten Sie, dass mit diesem Code die Zertifikate in cacerts wird nicht verwendet. Diese besondere HttpsURLConnection vertraut nur diesem spezifischen Zertifikat.

  • Die [android documentation] (developer.android.com/training/articles/security-ssl#SelfSigned) gibt im Grunde Ihre Erklärung. Es gibt nur ein bisschen mehr Erklärung, Code und Warnungen.

    – Daniel

    31. Juli 2020 um 14:36 ​​Uhr

  • Meiner Meinung nach sollte dies die akzeptierte Antwort sein! Der Vorteil dieser Methode besteht darin, dass Sie alles programmgesteuert ausführen und dennoch die Sicherheit aufrechterhalten und den Vertrauensspeicher der JRE nicht ändern. Option 2 aus der akzeptierten Antwort ist aus Sicherheitsgründen völlig falsch. Vielen Dank für die Bereitstellung dieser Lösung!

    – handelnunterdc

    19. August 2020 um 13:52 Uhr

  • Wenn jemand das Zertifikat in die JAR-Datei packen will, ersetzen Sie InputStream in der Methode generateCertificate dazu: this.class.getClassLoader().getResourceAsStream("server.crt")

    – Nikolasan

    20. April 2021 um 11:34 Uhr

Apache HttpClient 4.5 unterstützt das Akzeptieren selbstsignierter Zertifikate:

SSLContext sslContext = SSLContexts.custom()
    .loadTrustMaterial(new TrustSelfSignedStrategy())
    .build();
SSLConnectionSocketFactory socketFactory =
    new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> reg =
    RegistryBuilder.<ConnectionSocketFactory>create()
    .register("https", socketFactory)
    .build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);        
CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);

Dadurch wird eine SSL-Socket-Factory erstellt, die die verwendet TrustSelfSignedStrategyregistriert es bei einem benutzerdefinierten Verbindungsmanager und führt dann mit diesem Verbindungsmanager ein HTTP GET durch.

Ich stimme mit denen überein, die „tun Sie dies nicht in der Produktion“ singen, aber es gibt Anwendungsfälle für das Akzeptieren von selbstsignierten Zertifikaten außerhalb der Produktion; Wir verwenden sie in automatisierten Integrationstests, sodass wir SSL (wie in der Produktion) auch dann verwenden, wenn es nicht auf der Produktionshardware ausgeführt wird.

1646578643 876 Akzeptieren Sie das selbstsignierte SSL Zertifikat des Servers im Java Client
K.Nicholas

Ich habe dieses Problem an einen Zertifikatsanbieter gejagt, der nicht zu den standardmäßigen vertrauenswürdigen JVM-Hosts gehört JDK 8u74. Der Anbieter ist www.identrust.com, aber das war nicht die Domäne, mit der ich eine Verbindung herstellen wollte. Diese Domain hatte ihr Zertifikat von diesem Anbieter erhalten. Sehen Wird die Cross-Root-Abdeckung der Standardliste im JDK/JRE vertrauen? — lesen Sie ein paar Einträge. Siehe auch Welche Browser und Betriebssysteme unterstützen Let’s Encrypt.

Um also eine Verbindung zu der Domäne herzustellen, an der ich interessiert war und für die ein Zertifikat ausgestellt wurde identrust.com Ich habe die folgenden Schritte ausgeführt. Im Grunde musste ich die identrust.com (DST Root CA X3)-Zertifikat, dem die JVM vertrauen soll. Ich konnte das mit Apache HttpComponents 4.5 wie folgt tun:

1: Erhalten Sie das Zertifikat von indettrust unter Anweisungen zum Herunterladen der Zertifikatskette. Klicken Sie auf die DST-Root-CA X3 Verknüpfung.

2: Speichern Sie die Zeichenfolge in einer Datei namens „DST Root CA X3.pem“. Achten Sie darauf, die Zeilen “—–BEGIN CERTIFICATE—–” und “—–END CERTIFICATE—–” am Anfang und Ende der Datei hinzuzufügen.

3: Erstellen Sie mit dem folgenden Befehl eine Java-Keystore-Datei, cacerts.jks:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4: Kopieren Sie den resultierenden Keystore cacerts.jks in das Ressourcenverzeichnis Ihrer java/(maven)-Anwendung.

5: Verwenden Sie den folgenden Code, um diese Datei zu laden und an Apache 4.5 HttpClient anzuhängen. Dadurch wird das Problem für alle Domänen gelöst, von denen Zertifikate ausgestellt wurden indetrust.com util oracle schließt das Zertifikat in den JRE-Standardschlüsselspeicher ein.

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

Wenn das Projekt erstellt wird, wird die cacerts.jks in den Klassenpfad kopiert und von dort geladen. Ich habe zu diesem Zeitpunkt noch keine Tests mit anderen SSL-Sites durchgeführt, aber wenn der obige Code in diesem Zertifikat “verkettet” wird, funktionieren sie auch, aber ich weiß es auch nicht.

Referenz: Benutzerdefinierter SSL-Kontext und Wie akzeptiere ich ein selbstsigniertes Zertifikat mit einer Java HttpsURLConnection?

Anstatt die Standard-Socket-Factory festzulegen (was meiner Meinung nach eine schlechte Sache ist) wirkt sich dies nur auf die aktuelle Verbindung aus und nicht auf jede SSL-Verbindung, die Sie zu öffnen versuchen:

URLConnection connection = url.openConnection();
    // JMD - this is a better way to do it that doesn't override the default SSL factory.
    if (connection instanceof HttpsURLConnection)
    {
        HttpsURLConnection conHttps = (HttpsURLConnection) connection;
        // Set up a Trust all manager
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
        {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }

            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }

            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }
        } };

        // Get a new SSL context
        SSLContext sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        // Set our connection to use this SSL context, with the "Trust all" manager in place.
        conHttps.setSSLSocketFactory(sc.getSocketFactory());
        // Also force it to trust all hosts
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        // and set the hostname verifier.
        conHttps.setHostnameVerifier(allHostsValid);
    }
InputStream stream = connection.getInputStream();

  • Dein checkServerTrusted implementiert nicht die notwendige Logik, um dem Zertifikat tatsächlich zu vertrauen und Stellen Sie sicher, dass nicht vertrauenswürdige Zertifikate abgelehnt werden. Das könnte eine gute Lektüre sein: Der gefährlichste Code der Welt: Validierung von SSL-Zertifikaten in Nicht-Browser-Software.

    – jww

    4. Juni 2017 um 9:41 Uhr

  • Dein getAcceptedIssuers() Methode entspricht nicht der Spezifikation, und diese ‘Lösung’ bleibt radikal unsicher.

    – Benutzer207421

    4. Juni 2017 um 9:47 Uhr

Wenn ‘sie’ ein selbstsigniertes Zertifikat verwenden, liegt es an ihnen, die erforderlichen Schritte zu unternehmen, um ihren Server nutzbar zu machen. Konkret bedeutet das, dass sie Ihnen ihr Zertifikat auf vertrauenswürdige Weise offline zur Verfügung stellen. Also lass sie das tun. Diese importieren Sie dann mithilfe des Keytools in Ihren Truststore, wie im JSSE-Referenzhandbuch beschrieben. Denken Sie nicht einmal an den hier geposteten unsicheren TrustManager.

BEARBEITEN Zum Wohle der siebzehn (!) Downvoter und zahlreiche Kommentatoren unten, die offensichtlich nicht wirklich gelesen haben, was ich hier geschrieben habe, ist dies nicht eine Jeremiade gegen selbstsignierte Zertifikate. An selbstsignierten Zertifikaten ist nichts auszusetzen wenn richtig umgesetzt. Aber, Der richtige Weg, sie zu implementieren, ist die Zustellung des Zertifikats sicher über einen Offline-Prozess, Anstatt über den nicht authentifizierten Kanal werden sie zur Authentifizierung verwendet. Das ist doch offensichtlich? Es ist sicherlich für jede sicherheitsbewusste Organisation, für die ich je gearbeitet habe, offensichtlich, von Banken mit Tausenden von Filialen bis hin zu meinen eigenen Unternehmen. Die clientseitige codebasierte „Lösung“ des Vertrauens alle Zertifikate, einschließlich selbstsignierter Zertifikate, die von absolut jeder Person oder einer willkürlichen Stelle, die sich selbst als Zertifizierungsstelle einrichtet, signiert wurden ipso facto nicht sicher. Es spielt nur auf Sicherheit. Es ist sinnlos. Sie führen ein privates, manipulationssicheres, antwortsicheres, injektionssicheres Gespräch mit … jemandem. Irgendjemand. Ein Mann in der Mitte. Ein Imitator. Irgendjemand. Sie können auch nur Klartext verwenden.

  • Dein checkServerTrusted implementiert nicht die notwendige Logik, um dem Zertifikat tatsächlich zu vertrauen und Stellen Sie sicher, dass nicht vertrauenswürdige Zertifikate abgelehnt werden. Das könnte eine gute Lektüre sein: Der gefährlichste Code der Welt: Validierung von SSL-Zertifikaten in Nicht-Browser-Software.

    – jww

    4. Juni 2017 um 9:41 Uhr

  • Dein getAcceptedIssuers() Methode entspricht nicht der Spezifikation, und diese ‘Lösung’ bleibt radikal unsicher.

    – Benutzer207421

    4. Juni 2017 um 9:47 Uhr

Wie implementiert man HorizontalScrollView wie Gallery
Asch Saini

Allen SSL-Zertifikaten vertrauen:- Sie können SSL umgehen, wenn Sie auf dem Testserver testen möchten. Verwenden Sie diesen Code jedoch nicht für die Produktion.

public static class NukeSSLCerts {
protected static final String TAG = "NukeSSLCerts";

public static void nuke() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] { 
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    X509Certificate[] myTrustedAnchors = new X509Certificate[0];  
                    return myTrustedAnchors;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {}

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {}
            }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
    } catch (Exception e) { 
    }
}

}

Bitte rufen Sie diese Funktion in der Funktion onCreate() in Activity oder in Ihrer Anwendungsklasse auf.

NukeSSLCerts.nuke();

Dies kann für Volley in Android verwendet werden.

  • Nicht ganz sicher, warum Sie abgelehnt werden, es sei denn, der Code funktioniert nicht. Vielleicht ist es die Annahme, dass Android irgendwie involviert ist, wenn die ursprüngliche Frage Android nicht markiert hat.

    – Lo Tan

    10. Juli 2018 um 14:43 Uhr

957160cookie-checkAkzeptieren Sie das selbstsignierte SSL-Zertifikat des Servers im Java-Client

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy