it-swarm.com.de

Java- und HTTPS-URL-Verbindung ohne Herunterladen des Zertifikats

Dieser Code stellt eine Verbindung zu einer HTTPS-Site her und ich gehe davon aus, dass ich das Zertifikat nicht verifiziere. Aber warum muss ich nicht lokal ein Zertifikat für die Site installieren? Sollte ich nicht ein Zertifikat lokal installieren und für dieses Programm laden müssen, oder wird es hinter den Abdeckungen heruntergeladen? Ist der Datenverkehr zwischen dem Client und dem Remote-Standort bei der Übertragung noch verschlüsselt?

import Java.io.BufferedReader;
import Java.io.InputStreamReader;
import Java.io.Reader;
import Java.net.URL;
import Java.net.URLConnection;
import Java.security.cert.X509Certificate;

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;

public class TestSSL {

    public static void main(String[] args) throws Exception {
        // Create a trust manager that does not validate certificate chains
        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) {
            }
        } };
        // Install the all-trusting trust manager
        final 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);

        URL url = new URL("https://www.google.com");
        URLConnection con = url.openConnection();
        final Reader reader = new InputStreamReader(con.getInputStream());
        final BufferedReader br = new BufferedReader(reader);        
        String line = "";
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }        
        br.close();
    } // End of main 
} // End of the class //
42
Berlin Brown

Der Grund, warum Sie ein Zertifikat nicht lokal laden müssen, besteht darin, dass Sie sich ausdrücklich dazu entschieden haben, das Zertifikat nicht zu überprüfen. Dieser Vertrauensmanager vertraut allen Zertifikaten.

Der Verkehr wird weiterhin verschlüsselt, aber Sie öffnen die Verbindung zu Man-In-The-Middle-Angriffen: Sie kommunizieren geheim mit jemandem, Sie sind sich nicht sicher, ob es sich dabei um den erwarteten Server oder um einen möglichen Angreifer handelt.

Wenn Ihr Serverzertifikat von einer bekannten Zertifizierungsstelle stammt, die Teil des Standardpakets von Zertifizierungsstellenzertifikaten ist, die im Lieferumfang der JRE enthalten sind (normalerweise cacerts-Datei, siehe JSSE-Referenzhandbuch), können Sie einfach den Standard-Trust-Manager verwenden hier alles einstellen.

Wenn Sie über ein bestimmtes Zertifikat (selbstsigniert oder von Ihrer eigenen Zertifizierungsstelle) verfügen, können Sie den Standard-Vertrauensmanager oder ein mit einem bestimmten Truststore initialisiertes Zertifikat verwenden. Sie müssen das Zertifikat jedoch explizit in Ihren Trust Store importieren (danach unabhängig) Verifizierung), wie in diese Antwort beschrieben. Sie könnten auch an dieser Antwort interessiert sein.

30
Bruno

Aber warum muss ich nicht lokal ein Zertifikat für die Site installieren?

Nun, der von Ihnen verwendete Code ist ausdrücklich dafür ausgelegt, das Zertifikat zu akzeptieren, ohne irgendwelche Prüfungen durchzuführen. Dies ist keine bewährte Methode ... aber wenn Sie dies tun möchten, müssen Sie (offensichtlich) kein Zertifikat installieren, das Ihr Code explizit ignoriert.

Sollte ich nicht ein Zertifikat lokal installieren und für dieses Programm laden müssen, oder wird es hinter den Abdeckungen heruntergeladen? 

Nein und nein. Siehe oben.

Ist der Datenverkehr zwischen dem Client und dem Remote-Standort bei der Übertragung noch verschlüsselt?

Ja, so ist es. Das Problem ist jedoch, dass Sie nicht wissen, ob Sie mit dem realen Server oder mit einer anderen Site sprechen, die vorgeben ist, da Sie ihm gesagt haben, dass Sie dem Zertifikat des Servers ohne Überprüfungen vertrauen möchten echter Server. Ob dies ein Problem ist, hängt von den Umständen ab.


Wenn wir den Browser als Beispiel verwenden, fordert ein Browser den Benutzer normalerweise nicht auf, explizit ein Zertifikat für jede besuchte SSL-Site zu installieren. 

Der Browser verfügt über eine Reihe von vertrauenswürdigen Stammzertifikaten, die vorinstalliert sind. Wenn Sie eine "https" -Site besuchen, kann der Browser meistens überprüfen, ob das Zertifikat der Site (letztendlich über die Zertifikatskette) durch eines dieser vertrauenswürdigen Zertifikate gesichert ist. Wenn der Browser das Zertifikat zu Beginn der Kette nicht als vertrauenswürdiges Zertifikat erkennt (oder wenn die Zertifikate veraltet oder auf andere Weise ungültig/unangemessen sind), wird eine Warnung angezeigt.

Java funktioniert genauso. Der Keystore der JVM verfügt über eine Reihe vertrauenswürdiger Zertifikate. Mit demselben Verfahren wird geprüft, ob das Zertifikat durch ein vertrauenswürdiges Zertifikat gesichert ist.

Unterstützt die Java-https-Client-API einen Mechanismus, um Zertifikatsinformationen automatisch herunterzuladen?

Wenn Sie zulassen, dass Anwendungen Zertifikate von beliebigen Orten herunterladen und (als vertrauenswürdig) im Systemschlüsselspeicher installieren, ist dies eine Sicherheitslücke.

12
Stephen C

Verwenden Sie den neuesten X509ExtendedTrustManager anstelle von X509Certificate wie hier empfohlen: Java.security.cert.CertificateException: Zertifikate entsprechen nicht den Algorithmuseinschränkungen .

    package javaapplication8;

    import Java.io.InputStream;
    import Java.net.Socket;
    import Java.net.URL;
    import Java.net.URLConnection;
    import Java.security.cert.CertificateException;
    import Java.security.cert.X509Certificate;
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLEngine;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509ExtendedTrustManager;

    /**
     *
     * @author hoshantm
     */
    public class JavaApplication8 {

        /**
         * @param args the command line arguments
         * @throws Java.lang.Exception
         */
        public static void main(String[] args) throws Exception {
            /*
             *  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
             */
            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509ExtendedTrustManager() {
                    @Override
                    public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

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

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

                    @Override
                    public void checkClientTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {

                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {

                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {

                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {

                    }

                }
            };

            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() {
                @Override
                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://10.52.182.224/cgi-bin/dynamic/config/panel.bmp");
            URLConnection con = url.openConnection();
            //Reader reader = new ImageStreamReader(con.getInputStream());

            InputStream is = new URL(url.toString()).openStream();

            // Whatever you may want to do next

        }

    }
3
Tarik

Java- und HTTPS-URL-Verbindung ohne Herunterladen des Zertifikats

Wenn Sie das Herunterladen des Serverzertifikats wirklich vermeiden möchten, verwenden Sie ein anonymes Protokoll wie Anonymous Diffie-Hellman (ADH). Das Serverzertifikat wird nicht mit ADH und Freunden gesendet.

Mit setEnabledCipherSuites wählen Sie ein anonymes Protokoll aus. Sie können die Liste der mit getEnabledCipherSuites verfügbaren Verschlüsselungssuiten anzeigen.

Related: Deshalb müssen Sie SSL_get_peer_certificate in OpenSSL aufrufen. Sie erhalten einen X509_V_OK mit einem anonymen Protokoll. Auf diese Weise prüfen Sie, ob ein Zertifikat im Austausch verwendet wurde.

Aber wie Bruno und Stephed C sagten, ist es eine schlechte Idee, die Kontrollen zu vermeiden oder ein anonymes Protokoll zu verwenden.


Eine andere Option ist die Verwendung von TLS-PSK oder TLS-SRP. Sie benötigen auch keine Serverzertifikate. (Aber ich glaube nicht, dass du sie benutzen kannst.).

Der Nachteil ist, dass Sie im System vorab bereitgestellt werden müssen, da TLS-PSK Pres-Shared Secret und TLS-SRP Secure Remote Password ist. Die Authentifizierung erfolgt nicht auf Server, sondern auf Gegenseitigkeit.

In diesem Fall wird die gegenseitige Authentifizierung durch eine Eigenschaft bereitgestellt, bei der beide Parteien das gemeinsame Geheimnis kennen und zum selben Premaster-Geheimnis gelangen. oder einer (oder beide) nicht und das Kanal-Setup schlägt fehl. Jede Partei beweist, dass die Kenntnis des Geheimnisses der "gegenseitige" Teil ist.

Schließlich machen TLS-PSK oder TLS-SRP keine dummen Dinge, wie das Passwort eines Benutzers wie in einer Web-App mithilfe von HTTP (oder über HTTPS). Deshalb sagte ich jede Partei beweist das Wissen um das Geheimnis ...

1
jww

Eine einfache, aber keine reine Java-Lösung besteht darin, von Java aus curl zu verwenden, wodurch Sie vollständige Kontrolle darüber haben, wie die Anforderung ausgeführt wird. Wenn Sie dies nur aus einfachen Gründen tun, können Sie mithilfe dieser Methode manchmal Zertifikatfehler ignorieren. In diesem Beispiel wird gezeigt, wie Sie eine Anforderung an einen sicheren Server mit einem gültigen oder ungültigen Zertifikat senden, ein Cookie übergeben und die Ausgabe mit curl von Java abrufen.

import Java.io.BufferedReader;
import Java.io.File;
import Java.io.IOException;
import Java.io.InputStreamReader;

public class MyTestClass
{
  public static void main(String[] args) 
  {
    String url = "https://www.google.com";
    String sessionId = "faf419e0-45a5-47b3-96d1-8c62b2a3b558";

    // Curl options are:
    // -k: ignore certificate errors
    // -L: follow redirects
    // -s: non verbose
    // -H: add a http header

    String[] command = { "curl", "-k", "-L", "-s", "-H", "Cookie: MYSESSIONCOOKIENAME=" + sessionId + ";", "-H", "Accept:*/*", url };
    String output = executeShellCmd(command, "/tmp", true, true);
    System.out.println(output);
  }

  public String executeShellCmd(String[] command, String workingFolder, boolean wantsOutput, boolean wantsErrors)
  {
    try
    {
      ProcessBuilder pb = new ProcessBuilder(command);
      File wf = new File(workingFolder);
      pb.directory(wf);

      Process proc = pb.start();
      BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
      BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

      StringBuffer sb = new StringBuffer();
      String newLine = System.getProperty("line.separator");
      String s;

      // read stdout from the command
      if (wantsOutput)
      {
        while ((s = stdInput.readLine()) != null)
        {
          sb.append(s);
          sb.append(newLine);
        }
      }

      // read any errors from the attempted command
      if (wantsErrors)
      {
        while ((s = stdError.readLine()) != null)
        {
          sb.append(s);
          sb.append(newLine);
        }
      }

      String result = sb.toString();

      return result;
    }
    catch (IOException e)
    {
      throw new RuntimeException("Problem occurred:", e);
    }
  }


}
1
Brad Parks

Wenn Sie ein Payment Gateway verwenden, um eine beliebige URL zu treffen, nur um eine Nachricht zu senden, habe ich eine Webansicht verwendet, indem Sie ihr folgten: Wie kann ich https-URL ohne Verwendung von SSL in Android Webview

und machen Sie in Ihrer Aktivität einen Webview mit Sichtbarkeit. Was Sie tun müssen: Laden Sie einfach diesen Webview ... 

 webViewForSms.setWebViewClient(new SSLTolerentWebViewClient());
                webViewForSms.loadUrl(" https://bulksms.com/" +
                        "?username=test&[email protected]&messageType=text&mobile="+
                        mobileEditText.getText().toString()+"&senderId=ATZEHC&message=Your%20OTP%20for%20A2Z%20registration%20is%20124");

Einfach.

Sie erhalten Folgendes: SSLTolerentWebViewClient über diesen Link: Wie kann die https-URL ohne Verwendung von SSL in der Android-Webansicht geladen werden? 

0
Amanpreet Singh