webentwicklung-frage-antwort-db.com.de

Wie kann man sich per HTTPS mit Jsoup verbinden?

Es funktioniert problemlos über HTTP, aber wenn ich versuche, eine HTTPS-Quelle zu verwenden, wird die folgende Ausnahme ausgelöst:

10-12 13:22:11.169: WARN/System.err(332): javax.net.ssl.SSLHandshakeException: Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
10-12 13:22:11.179: WARN/System.err(332):     at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:477)
10-12 13:22:11.179: WARN/System.err(332):     at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:328)
10-12 13:22:11.179: WARN/System.err(332):     at org.Apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.setupSecureSocket(HttpConnection.Java:185)
10-12 13:22:11.179: WARN/System.err(332):     at org.Apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:433)
10-12 13:22:11.189: WARN/System.err(332):     at org.Apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeConnection(HttpsURLConnectionImpl.Java:378)
10-12 13:22:11.189: WARN/System.err(332):     at org.Apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.Java:205)
10-12 13:22:11.189: WARN/System.err(332):     at org.Apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.Java:152)
10-12 13:22:11.189: WARN/System.err(332):     at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.Java:377)
10-12 13:22:11.189: WARN/System.err(332):     at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.Java:364)
10-12 13:22:11.189: WARN/System.err(332):     at org.jsoup.helper.HttpConnection.execute(HttpConnection.Java:143)

Hier ist der entsprechende Code:

try {
    doc = Jsoup.connect("https url here").get();
} catch (IOException e) {
    Log.e("sys","coudnt get the html");
    e.printStackTrace();
}
22
jfisk

Wenn Sie dies auf die richtige Weise tun möchten und/oder Sie müssen nur mit einer Site umgehen, müssen Sie im Wesentlichen das SSL-Zertifikat der betreffenden Website erwerben und in Ihren Java-Schlüsselspeicher importieren. Dies führt zu einer JKS-Datei, die Sie vor der Verwendung von Jsoup (oder Java.net.URLConnection) als SSL-Vertrauensspeicher festlegen. 

Sie können das Zertifikat aus dem Speicher Ihres Webbrowsers beziehen. Nehmen wir an, Sie verwenden Firefox.

  1. Gehen Sie mit Firefox auf die betreffende Website. Dies ist in Ihrem Fall https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
  2. Links in der Adressleiste wird "uconn.edu" blau angezeigt (dies weist auf ein gültiges SSL-Zertifikat hin).
  3. Klicken Sie darauf, um Details anzuzeigen, und klicken Sie dann auf die Schaltfläche Weitere Informationen.
  4. Klicken Sie im angezeigten Sicherheitsdialogfeld auf die Schaltfläche View Certificate.
  5. Wechseln Sie in der angezeigten Zertifikatsanzeige zur Registerkarte Details.
  6. Klicken Sie auf das tiefste Element der Zertifikathierarchie, in diesem Fall "web2.uconn.edu", und klicken Sie anschließend auf die Schaltfläche Export.

Jetzt haben Sie eine web2.uconn.edu.crt-Datei.

Öffnen Sie als Nächstes den Befehl Prompt und importieren Sie ihn mit dem Befehl keytool (er ist Teil der JRE) in den Java-Schlüsselspeicher:

keytool -import -v -file /path/to/web2.uconn.edu.crt -keystore /path/to/web2.uconn.edu.jks -storepass drowssap

Der -file muss auf den Ort der gerade heruntergeladenen .crt-Datei zeigen. -keystore muss auf den Speicherort der generierten .jks-Datei verweisen (die Sie wiederum als SSL-Truststore festlegen möchten). Der -storepass ist erforderlich. Sie können ein beliebiges Kennwort eingeben, sofern es mindestens 6 Zeichen enthält.

Nun haben Sie eine web2.uconn.edu.jks-Datei. Sie können es schließlich als SSL-Truststore festlegen, bevor Sie eine Verbindung herstellen, wie folgt:

System.setProperty("javax.net.ssl.trustStore", "/path/to/web2.uconn.edu.jks");
Document document = Jsoup.connect("https://web2.uconn.edu/driver/old/timepoints.php?stopid=10").get();
// ...

Als völlig andere Alternative, insbesondere wenn Sie mit mehreren Sites arbeiten müssen (d. H. Sie erstellen einen World Wide Web-Crawler), können Sie Jsoup (im Grunde Java.net.URLConnection) auch anweisen, blind auf alle SSL-Zertifikate zu vertrauen. Siehe auch Abschnitt "Umgang mit nicht vertrauenswürdigen oder falsch konfigurierten HTTPS-Sites" ganz unten in dieser Antwort: Verwendung von Java.net.URLConnection zum Auslösen und Verarbeiten von HTTP-Anforderungen

52
BalusC

In meinem Fall musste ich nur die .validateTLSCertificates (false) in meine Verbindung einfügen

Document doc  = Jsoup.connect(httpsURLAsString)
            .timeout(60000).validateTLSCertificates(false).get();

Ich musste auch die Lesezeit erhöhen, aber ich denke, das ist irrelevant

11
johnmerm

Ich bin über die Antworten hier und in der verknüpften Frage in meiner Suche gestolpert und möchte zwei Informationen hinzufügen, da die akzeptierte Antwort nicht zu meinem ziemlich ähnlichen Szenario passt, aber es gibt eine zusätzliche Lösung, die auch in diesem Fall passt (cert und Hostname stimmen für Testsysteme nicht überein).

  1. Es gibt eine Github-Anforderung, um eine solche Funktionalität hinzuzufügen. Vielleicht wird das Problem bald gelöst: https://github.com/jhy/jsoup/pull/343 Edit: Die Github-Anforderung wurde gelöst, und die Methode zum Deaktivieren der Zertifikatvalidierung lautet: validateTLSCertificates (boolean validate) )
  2. Basierend auf http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-Java-ssl-connections/ habe ich eine Lösung gefunden, die scheinbar funktioniert (zumindest in mein Szenario, in dem jsoup 1.7.3 als Teil einer Maven-Task aufgerufen wird). Ich wickelte es in eine Methode disableSSLCertCheck() ein, die ich vor dem allerersten Jsoup.connect () aufrufe.

Bevor Sie diese Methode verwenden, sollten Sie sich wirklich sicher sein, dass Sie verstehen, was Sie dort tun - SSL-Zertifikate nicht zu prüfen, ist eine wirklich dumme Sache. Verwenden Sie immer korrekte SSL-Zertifikate für Ihre Server, die von einer allgemein anerkannten Zertifizierungsstelle signiert sind. Wenn Sie sich eine allgemein akzeptierte Zertifizierungsstelle nicht leisten können, verwenden Sie dennoch korrekte SSL-Zertifikate. Die von @BalusC akzeptierte Antwort oben. Wenn Sie keine korrekten SSL-Zertifikate konfigurieren können (was in Produktionsumgebungen niemals der Fall sein sollte), könnte die folgende Methode funktionieren:

    private void disableSSLCertCheck() throws NoSuchAlgorithmException, KeyManagementException {
    // 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
    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);
    }
8
NextThursday

Ich hatte das gleiche Problem, nahm aber den faulen Weg - sag deiner App, dass sie das Zertifikat ignoriert und mache trotzdem weiter.

Ich habe den Code hier: Wie verwende ich eine lokale HTTPS-URL in Java?

Sie müssen diese Klassen importieren, damit sie funktioniert:

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;

Führen Sie diese Methode einfach irgendwo aus, bevor Sie versuchen, die Verbindung herzustellen und voila, sie vertraut einfach dem Zertifikat, egal was passiert. Natürlich ist dies keine Hilfe, wenn Sie wirklich sicherstellen möchten, dass das Zertifikat echt ist, aber gut für die Überwachung Ihrer eigenen internen Websites usw.

3
RobinCJ

Seit dieser Lösung:

Document doc  = Jsoup.connect(httpsURLAsString)
            .timeout(60000).validateTLSCertificates(false).get();

Zeigt jetzt Verfallswarnungen an und wird in Kürze entfernt. Alternative Option (im Grunde die gleiche Idee wie in Antwort ), aber zum Unterdrücken von Zertifikatwarnungen für mit einer bestimmten JSoup-Verbindung:

Kotlin


val document = Jsoup.connect("url")
        .sslSocketFactory(socketFactory())
        .get()


private fun socketFactory(): SSLSocketFactory {
    val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
        @Throws(CertificateException::class)
        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        @Throws(CertificateException::class)
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        override fun getAcceptedIssuers(): Array<X509Certificate> {
            return arrayOf()
        }
    })

    try {
        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(null, trustAllCerts, Java.security.SecureRandom())
        return sslContext.socketFactory
    } catch (e: Exception) {
        when (e) {
            is RuntimeException, is KeyManagementException -> {
                throw RuntimeException("Failed to create a SSL socket factory", e)
            }
            else -> throw e
        }
    }
}

Java



 Document document = Jsoup.connect("url")
        .sslSocketFactory(socketFactory())
        .get();


  private SSLSocketFactory socketFactory() {
    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) {
      }
    }};

    try {
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
      return sslContext.getSocketFactory();
    } catch (NoSuchAlgorithmException | KeyManagementException e) {
      throw new RuntimeException("Failed to create a SSL socket factory", e);
    }
  }

NB. Wie bereits erwähnt, ist das Ignorieren von Zertifikaten keine gute Idee.

2

Ich hatte dieses Problem nur in dev-Umgebung. Die zu lösende Lösung bestand darin, einige Markierungen hinzuzufügen, um SSL an der VM zu ignorieren:

-Ddeployment.security.TLSv1.1=false 
-Ddeployment.security.TLSv1.2=false
0
pawelini1

Ich bin kein Experte auf diesem Gebiet, aber ich habe eine ähnliche Ausnahme gefunden, als ich versuchte, über HTTPS mit Java.net-APIs eine Verbindung zu einer Website herzustellen. Wenn Sie eine Website mit HTTPS aufrufen, erledigt der Browser eine Menge Arbeit für SSL-Zertifikate. Wenn Sie jedoch manuell eine Verbindung zu Sites herstellen (mithilfe von HTTP-Anforderungen manuell), müssen alle Arbeiten noch erledigt werden. Jetzt weiß ich nicht genau, was das alles genau ist, aber es hat damit zu tun, Zertifikate herunterzuladen und sie dort zu platzieren, wo sie von Java gefunden werden können. Hier ist ein Link, der Sie hoffentlich in die richtige Richtung weist.

http://confluence.atlassian.com/display/JIRA/Anschließen von + an+SSL+ -Dienste

0
jeff

Ich hatte das gleiche Problem mit Jsoup, ich konnte keine Verbindung herstellen und das Dokument für https-URLs abrufen, aber als ich meine JDK-Version von 1.7 auf 1.8 geändert habe, wurde das Problem behoben.

Es kann dir helfen :) 

0
ramkishorbajpai