2011-10-12 11 views
15

To działa dobrze przez protokół HTTP, ale gdy próbuję i wykorzystywać źródła HTTPS rzuca następujący wyjątek:Jak połączyć się przez HTTPS za pomocą Jsoup?

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) 

Oto odpowiedni kod:

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

Odpowiedz

44

Jeśli chcesz zrobić to we właściwy sposób, i/lub trzeba do czynienia z jednym tylko miejscu, to w zasadzie trzeba chwycić certyfikat SSL witryny w pytaniu i importować go w Magazyn kluczy Java. Spowoduje to, że plik JKS zostanie ustawiony jako magazyn zaufanych certyfikatów SSL przed użyciem Jsoup (lub java.net.URLConnection).

Możesz pobrać certyfikat ze sklepu przeglądarki internetowej. Załóżmy, że używasz przeglądarki Firefox.

  1. Przejdź do witryny w kwestii korzystania z przeglądarki Firefox, która jest w twoim przypadku https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
  2. lewej w pasku adresu zobaczysz „uconn.edu” w kolorze niebieskim (oznacza to ważny certyfikat SSL)
  3. Kliknij na nim, aby uzyskać szczegółowe informacje, a następnie kliknij przycisk Więcej informacji.
  4. W wyświetlonym oknie dialogowym bezpieczeństwa kliknij przycisk 10 Zobacz certyfikat.
  5. W wyświetlonym panelu certyfikatu przejdź do zakładki Szczegóły.
  6. Kliknij najgłębszy element hierarchii certyfikatów, który jest w tym przypadku "web2.uconn.edu", a na koniec kliknij przycisk Eksportuj Eksportuj.

Teraz masz plik web2.uconn.edu.crt.

Następnie otwórz wiersz polecenia i importować go w magazynie kluczy Java z wykorzystaniem komendy keytool (to część JRE):

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

-file musi wskazać lokalizację pliku .crt którego właśnie pobrane. Numer -keystore musi wskazywać położenie wygenerowanego pliku .jks (który z kolei chcesz ustawić jako magazyn zaufanych certyfikatów SSL). Wymagane jest -storepass, wystarczy wpisać dowolne hasło, o ile ma co najmniej 6 znaków.

Teraz masz plik web2.uconn.edu.jks.Można wreszcie ustawić go jako magazynu zaufanych certyfikatów SSL przed połączeniem się następująco:

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(); 
// ... 

Jako zupełnie innej alternatywy, szczególnie gdy trzeba radzić sobie z wielu stron (czyli podczas tworzenia przeszukiwacza sieci WWW), możesz także poinstruować Jsoup (w zasadzie, java.net.URLConnection), aby ślepo zaufał wszystkim certyfikatom SSL. Zobacz także sekcję "Radzenie sobie z niezaufanymi lub źle skonfigurowanymi witrynami HTTPS" na samym końcu tej odpowiedzi: Using java.net.URLConnection to fire and handle HTTP requests

+0

tylko znaleźć na to pytanie ...... mam ten sam problem, ale co mam zrobić z plikiem crt jeśli ja używam Eclipse? jaka jest alternatywa keytool dla eclipse? – gedo

+0

Wygląda na to, że firefox pozwala również na korzystanie z certyfikatu na poziomie domeny do odwiedzania subdomen. Jednak JSoup nie pozwoli na to. Wszelkie sugestie, aby to naprawić? – bvdb

+0

Dzięki za napiwek! Nadal masz problem z załadowaniem pliku .jdk. Wygląda na to, że nie ma go w katalogu zewnętrznym/crt. Plik f = nowy Plik (Environment.getRootDirectory() + "/crt/www.loterie.lu.jks"); \t if (f.isFile()) \t \t \t Log.i ("JSOUP", "Znaleziono plik certyfikatu"); \t \t inny \t \t \t Log.i ("JSOUP", "BŁĄD: Certyfikat nie znaleziono pliku" + f.getAbsolutePath()); – Dax

0

nie jestem ekspertem w tej dziedzinie ale wystąpił podobny wyjątek podczas próby połączenia się ze stroną za pośrednictwem protokołu HTTPS przy użyciu interfejsów API java.net. Przeglądarka wykonuje dla Ciebie wiele pracy w zakresie certyfikatów SSL podczas odwiedzania witryny za pomocą protokołu HTTPS. Jednak, gdy ręcznie łączysz się z witrynami (ręcznie za pomocą żądań HTTP), wszystkie te działania nadal muszą zostać wykonane. Teraz nie wiem, co to dokładnie jest, ale ma to związek z pobieraniem certyfikatów i umieszczaniem ich tam, gdzie może je znaleźć. Oto link, który, mam nadzieję, wskaże ci właściwy kierunek.

http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services

2

Miałem ten sam problem, ale skorzystałem z leniwej trasy - powiedz swojej aplikacji, aby zignorowała certyfikat i kontynuowała.

mam kod stąd: How do I use a local HTTPS URL in java?

Będziesz musiał importować te lekcje do jego pracy:

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; 

Wystarczy uruchomić tę metodę gdzieś przed próbą nawiązania połączenia i voila , po prostu wierzy w certyfikat bez względu na wszystko. Oczywiście to nie jest żadna pomoc, jeśli chcesz mieć pewność, że certyfikat jest prawdziwy, ale dobry do monitorowania twoich własnych wewnętrznych stron internetowych itd.

7

Natknąłem się na odpowiedzi tutaj i na powiązane pytanie w moim wyszukiwaniu i chcę dodać dwie części informacji, ponieważ zaakceptowana odpowiedź nie pasuje do mojego całkiem podobnego scenariusza, ale istnieje dodatkowe rozwiązanie, które pasuje nawet w tym przypadku (certyfikaty i nazwy hosta nie pasują do systemów testowych).

  1. Istnieje żądanie Github, aby dodać taką funkcję. Więc może wkrótce problem zostanie rozwiązany: https://github.com/jhy/jsoup/pull/343 edit: Żądanie Github został rozwiązany i sposób, aby wyłączyć sprawdzanie certyfikatu wynosi: validateTLSCertificates (logiczna walidacji)
  2. oparciu o http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/ znalazłem rozwiązanie, które wydaje się działać (przynajmniej w moim scenariusz, w którym jsoup 1.7.3 jest wywoływany jako część zadania maven). Zawinąłem go w metodzie disableSSLCertCheck(), którą wywołuję przed pierwszym Jsoup.connect().

Przed użyciem tej metody, powinieneś być pewien, że wiesz, co robisz, nie - nie sprawdzanie certyfikatów SSL jest naprawdę głupie. Zawsze używaj poprawnych certyfikatów SSL dla serwerów, które są podpisane przez powszechnie akceptowany urząd certyfikacji. Jeśli nie stać Cię na powszechnie akceptowany urząd certyfikacji, użyj poprawnych certyfikatów SSL, ale z @BalusC zaakceptuj powyższą odpowiedź. Jeśli nie można skonfigurować odpowiednie certyfikaty SSL (które nigdy nie powinno być w przypadku środowisk produkcyjnych) następująca metoda może działać:

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); 
    } 
+0

dla następnych czytelników ... należy zachować ostrożność: zmienia to zachowanie DOWOLNEJ klasy w aplikacji, która tworzy intencję połączenia HTTP, nie tylko w klasie, w której ją uruchomiono. – exoddus

+0

W jaki sposób mogę zintegrować to rozwiązanie z metodą Jsoup.connect (httpsurl) .get()? – Luke

-3

Spróbuj następujących (wystarczy umieścić go przed Jsoup.connect("https://example.com"):

Authenticator.setDefault(new Authenticator() { 
     @Override 
     protected PasswordAuthentication getPasswordAuthentication() { 
      return new PasswordAuthentication(username, password.toCharArray()); 
     } 
    }); 
1

W moja sprawa, wszystko, co potrzebne do zrobienia było dodać .validateTLSCertificates (fałsz) w moim związku

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

miałem też zwiększyć limit czasu czytać, ale myślę, to nie ma znaczenia

0

byłem w obliczu tego samego problemu z Jsoup, nie byłem w stanie połączyć i uzyskać dokument dla HTTPS, ale kiedy zmienił moją wersję JDK od 1,7 do 1,8, problem został rozwiązany.

To może pomóc :)

Powiązane problemy