web-dev-qa-db-fra.com

Comment se connecter via HTTPS avec Jsoup?

Cela fonctionne bien sur HTTP, mais lorsque j'essaie d'utiliser une source HTTPS, elle génère l'exception suivante:

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)

Voici le code pertinent:

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

Si vous voulez le faire correctement et/ou si vous ne devez gérer qu'un seul site, vous devez récupérer le certificat SSL du site Web en question et l'importer dans votre magasin de clés Java. Cela se traduira par un fichier JKS que vous définissez à son tour comme magasin de clés de confiance SSL avant d'utiliser Jsoup (ou Java.net.URLConnection). 

Vous pouvez récupérer le certificat dans la boutique de votre navigateur. Supposons que vous utilisez Firefox.

  1. Accédez au site Web en question en utilisant Firefox, qui est dans votre cas https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
  2. A gauche dans la barre d'adresse, vous verrez "uconn.edu" en bleu (cela indique un certificat SSL valide)
  3. Cliquez dessus pour plus de détails puis cliquez sur le bouton Plus d'informations.
  4. Dans le dialogue de sécurité qui apparaît, cliquez sur le bouton Voir le certificat.
  5. Dans le panneau de certificat qui apparaît, accédez à l'onglet Détails.
  6. Cliquez sur l'élément le plus profond de la hiérarchie du certificat, qui est dans ce cas "web2.uconn.edu", puis cliquez sur le bouton Exporter.

Maintenant, vous avez un fichier web2.uconn.edu.crt.

Ensuite, ouvrez l'invite de commande et importez-la dans le magasin de clés Java à l'aide de la commande keytool (elle fait partie de JRE):

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

Le -file doit pointer vers l'emplacement du fichier .crt que vous venez de télécharger. Le -keystore doit pointer vers l'emplacement du fichier .jks généré (que vous souhaitez à son tour définir comme magasin de clés de sécurité SSL). Le -storepass est requis, vous pouvez simplement entrer le mot de passe que vous voulez tant qu'il contient au moins 6 caractères.

Maintenant, vous avez un fichier web2.uconn.edu.jks. Vous pouvez enfin le définir comme trust store SSL avant de vous connecter comme suit:

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

Une alternative complètement différente, en particulier lorsque vous devez gérer plusieurs sites (par exemple, vous créez un robot d'exploration du Web), vous pouvez également demander à Jsoup (en gros, Java.net.URLConnection) de faire une confiance aveugle à tous les certificats SSL. Voir aussi la section "Gestion des sites HTTPS non fiables ou mal configurés" tout au bas de cette réponse: Utilisation de Java.net.URLConnection pour déclencher et gérer les requêtes HTTP

52
BalusC

Dans mon cas, tout ce que je devais faire était d'ajouter le .validateTLSCertificates (false) à ma connexion.

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

J'ai également dû augmenter le délai de lecture, mais je pense que cela n'a pas d'importance

11
johnmerm

Je suis tombé sur les réponses ici et dans la question liée dans ma recherche et je souhaite ajouter deux informations, car la réponse acceptée ne correspond pas à mon scénario très similaire, mais il existe une solution supplémentaire qui convient même dans ce cas (cert et le nom d’hôte ne correspondent pas pour les systèmes de test).

  1. Il y a une demande de github d'ajouter une telle fonctionnalité. Alors, le problème sera peut-être bientôt résolu: https://github.com/jhy/jsoup/pull/343 Edit: la requête Github a été résolue et la méthode pour désactiver la validation du certificat est la suivante: validateTLSCertificates (boolean validate )
  2. Basé sur http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-Java-ssl-connections/ J'ai trouvé une solution qui semble fonctionner (du moins dans mon scénario où jsoup 1.7.3 est appelé dans le cadre d’une tâche maven). Je l'ai encapsulé dans une méthode disableSSLCertCheck() que j'ai appelée avant le tout premier Jsoup.connect ().

Avant d'utiliser cette méthode, vous devez être vraiment sûr de bien comprendre ce que vous faites là-bas - ne pas vérifier les certificats SSL est une chose vraiment stupide. Utilisez toujours des certificats SSL corrects pour vos serveurs, signés par une autorité de certification couramment acceptée. Si vous ne pouvez pas vous permettre une autorité de certification communément acceptée, utilisez les certificats SSL appropriés avec néanmoins la réponse acceptée de @BalusC ci-dessus. Si vous ne pouvez pas configurer les certificats SSL corrects (ce qui ne devrait jamais être le cas dans les environnements de production), la méthode suivante pourrait fonctionner:

    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

J'ai eu le même problème, mais j'ai pris la route paresseuse. Dites à votre application d'ignorer le certificat et de continuer malgré tout.

J'ai le code ici: Comment utiliser une URL HTTPS locale en Java?

Vous devrez importer ces classes pour que cela fonctionne:

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;

Il suffit d’exécuter cette méthode quelque part avant d’essayer d’établir la connexion et le tour est joué, il se fie à la cert, quoi qu’il en soit. Bien sûr, ce n'est pas une aide si vous voulez réellement vous assurer que le certificat est réel, mais bon pour surveiller vos propres sites Web internes, etc.

3
RobinCJ

J'ai eu ce problème uniquement dans l'environnement de développement. La solution à ce problème consistait simplement à ajouter quelques indicateurs pour ignorer SSL sur les ordinateurs virtuels:

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

Je ne suis pas un expert dans ce domaine, mais j'ai rencontré une exception similaire lors de la tentative de connexion à un site Web via HTTPS à l'aide d'API Java.net. Le navigateur effectue beaucoup de travail pour vous en ce qui concerne les certificats SSL lorsque vous visitez un site utilisant HTTPS. Cependant, lorsque vous vous connectez manuellement à des sites (à l'aide de requêtes HTTP manuellement), tout ce qui reste à faire reste à faire. Maintenant, je ne sais pas en quoi consiste exactement tout ce travail, mais il s’agit de télécharger des certificats et de les placer là où Java peut les trouver. Voici un lien qui, espérons-le, vous dirigera dans la bonne direction.

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

0
jeff

Je faisais face au même problème avec Jsoup, je ne pouvais pas me connecter et obtenir le document pour les URL https, mais lorsque j'ai changé ma version de JDK de 1.7 à 1.8, le problème a été résolu.

Cela peut vous aider :) 

0
ramkishorbajpai