2011-10-12 14 views
15

Sta funzionando benissimo su HTTP, ma quando provo e utilizzare una fonte di HTTPS si getta la seguente eccezione:Come connettersi tramite HTTPS usando 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) 

Ecco il codice rilevante:

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

risposta

44

Se si vuole fare nel modo giusto, e/o avete bisogno di trattare con un solo sito, allora è fondamentalmente bisogno di afferrare il certificato SSL del sito web in questione e importarlo nel vostro Keystore Java. Ciò comporterà un file JKS che a sua volta verrà impostato come archivio sicuro SSL prima di utilizzare Jsoup (o java.net.URLConnection).

È possibile prelevare il certificato dal negozio del tuo browser. Supponiamo che tu stia utilizzando Firefox.

  1. Vai al sito in questione usando Firefox, che è nel tuo caso https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
  2. sinistra nella barra degli indirizzi si vedrà "uconn.edu" in blu (questo indica un certificato SSL valido)
  3. Fare clic su di esso per i dettagli e quindi fare clic sul pulsante Ulteriori informazioni.
  4. Nella finestra di dialogo di sicurezza visualizzata, fare clic sul pulsante Visualizza certificato.
  5. Nel pannello dei certificati visualizzato, passare alla scheda Dettagli.
  6. Fare clic sull'elemento più profondo della gerarchia di certificati, che è in questo caso "web2.uconn.edu" e infine fare clic sul pulsante Export.

Ora hai un file web2.uconn.edu.crt.

Quindi, aprire il prompt dei comandi e importarlo nell'archivio chiavi Java utilizzando il comando keytool (è parte del JRE):

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

Il -file deve puntare alla posizione del file .crt cui si appena scaricato. Il -keystore deve puntare alla posizione del file .jks generato (che a sua volta si desidera impostare come archivio sicuro SSL). È richiesto il -storepass, è sufficiente inserire la password che si desidera purché sia ​​composta da almeno 6 caratteri.

Ora hai un file web2.uconn.edu.jks.È infine possibile impostare come negozio SSL di fiducia prima di collegare nel modo seguente:

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

Come una completamente diversa alternativa, in particolare quando è necessario affrontare con più siti (per esempio, si sta creando un world wide web crawler), quindi puoi anche istruire Jsoup (in pratica, java.net.URLConnection) a fidarsi ciecamente di tutti i certificati SSL. Vedi anche la sezione "Gestire siti HTTPS non affidabili o mal configurati" nella parte inferiore di questa risposta: Using java.net.URLConnection to fire and handle HTTP requests

+0

appena trovato questa domanda ...... Ho lo stesso problema, ma cosa devo fare con il file crt se io sto usando eclissi? qual è l'alternativa di keytool per eclipse? – gedo

+0

Apparentemente firefox consente l'utilizzo di un certificato a livello di dominio per visitare anche i sottodomini. Tuttavia, JSoup non lo consentirà. Qualche suggerimento per risolvere questo problema? – bvdb

+0

Grazie per il suggerimento! Ancora un problema nel caricare il file .jdk. Sembra che non sia incluso o accessibile da una directory esterna/crt. File f = new File (Environment.getRootDirectory() + "/crt/www.loterie.lu.jks"); \t \t if (f.isFile()) \t \t \t Log.i ("JSOUP", "File di certificato trovato"); \t \t altro \t \t \t Log.i ("JSOUP", "ERRORE: file del certificato non trovato" + f.getAbsolutePath()); – Dax

0

Non sono un esperto in questo campo ma mi sono imbattuto in un'eccezione simile quando provavo a connettermi a un sito web su HTTPS usando le API java.net. Il browser fa molto per te per quanto riguarda i certificati SSL quando visiti un sito usando HTTPS. Tuttavia, quando ci si connette manualmente ai siti (utilizzando manualmente le richieste HTTP), tutto ciò che funziona deve ancora essere fatto. Ora non so cosa sia esattamente questo lavoro, ma ha a che fare con il download dei certificati e il loro inserimento in Java. Ecco un link che, si spera, ti indicherà la giusta direzione.

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

2

Ho avuto lo stesso problema ma ho preso la via lenta - dire alla tua app di ignorare il certificato e proseguire comunque.

ho ricevuto il codice da qui: How do I use a local HTTPS URL in java?

Dovrete importare queste classi per farlo funzionare:

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; 

Basta eseguire che il metodo da qualche parte prima di provare a effettuare la connessione e voilà , si fida solo del cert, non importa cosa. Naturalmente questo non è di alcun aiuto se si vuole realmente assicurarsi che il certificato sia reale, ma buono per monitorare i propri siti Web interni ecc.

7

Mi sono imbattuto nelle risposte qui e nella domanda collegata nella mia ricerca e voglio aggiungere due informazioni, poiché la risposta accettata non si adatta al mio scenario abbastanza simile, ma c'è una soluzione aggiuntiva che si adatta anche in quel caso (cert e hostname non corrispondono per i sistemi di test).

  1. C'è una richiesta di github per aggiungere una tale funzionalità. Così forse presto il problema sarà risolto: https://github.com/jhy/jsoup/pull/343 edit: richiesta Github è stato risolto e il metodo per disabilitare la convalida dei certificati è: validateTLSCertificates (convalidare booleana)
  2. sulla base di http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/ ho trovato una soluzione che sembra funzionare (almeno nel mio scenario in cui jsoup 1.7.3 viene chiamato come parte di un task maven). L'ho avvolto in un metodo disableSSLCertCheck() che chiamo prima del primo Jsoup.connect().

Prima di utilizzare questo metodo, si dovrebbe essere veramente sicuri di aver compreso ciò che si fa lì - non controllare i certificati SSL è una cosa davvero stupida. Usa sempre i certificati SSL corretti per i tuoi server che sono firmati da una CA comunemente accettata. Se non puoi permetterti una CA comunemente accettata, usa i certificati SSL corretti, tuttavia con la risposta sopra accettata da @BalusC. Se non è possibile configurare i certificati SSL corretti (che non dovrebbe mai essere il caso in ambienti di produzione) il seguente metodo potrebbe funzionare:

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

per i prossimi lettori ... fai attenzione: modifica il comportamento di QUALSIASI classe nella tua app che crea un'intestazione di HttpsURLConnection, non solo nella classe in cui lo esegui. – exoddus

+0

Come si integra questa soluzione con il metodo Jsoup.connect (httpsurl) .get()? – Luke

-3

Prova a seguire (appena messo prima Jsoup.connect("https://example.com"):

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

In il mio caso, tutto quello che dovevo fare era di aggiungere le .validateTLSCertificates (false) nella mia connessione

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

ho anche dovuto aumentare il timeout di lettura ma penso questo è irrilevante

0

Ero di fronte allo stesso problema con Jsoup, non ero in grado di connettermi e ottenere il documento per gli URL https ma quando ho cambiato la mia versione JDK dalla 1.7 alla 1.8, il problema è stato risolto.

Essa può aiutare :)

Problemi correlati