Comment utiliser HttpClient avec TOUT cert ssl, quelle que soit la « mauvaise » est


Brad Parks:

J'utilise Apache HttpClient dans un robot Web qui est seulement pour l' exploration des données publiques.

Je voudrais qu'il soit en mesure de les sites d'exploration avec des certificats non valides, peu importe comment invalide.

Mon robot ne sera pas passe dans tous les noms d'utilisateur, mots de passe, etc. et aucune donnée sensible est envoyé ou reçu.

Pour ce cas d'utilisation, je ramper la httpversion d'un site si elle existe, mais parfois non bien sûr.

Comment cela peut - il être fait avec Apache HttpClient ?

J'ai essayé quelques suggestions comme celui - ci , mais ils ne parviennent toujours à quelques certs invalides, par exemple:

failed for url:https://dh480.badssl.com/, reason:java.lang.RuntimeException: Could not generate DH keypair
failed for url:https://null.badssl.com/, reason:Received fatal alert: handshake_failure
failed for url:https://rc4-md5.badssl.com/, reason:Received fatal alert: handshake_failure
failed for url:https://rc4.badssl.com/, reason:Received fatal alert: handshake_failure
failed for url:https://superfish.badssl.com/, reason:Connection reset

Notez que je l' ai essayé avec mon $JAVA_HOME/jre/lib/security/java.securityde fichier jdk.tls.disabledAlgorithmsde jeu à rien, pour que tel soit pas un problème, et je reçois encore des échecs comme ci - dessus.

user3474985:

La réponse courte à votre question, qui est de faire confiance spécifiquement tous certs, serait d'utiliser la TrustAllStrategy et faire quelque chose comme ceci:

SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, new TrustAllStrategy());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
        sslContextBuilder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
        socketFactory).build();

Mais ... un cert invalide ne peut pas être votre principal problème. Un handshake_failure peut se produire pour plusieurs raisons , mais dans mon expérience , il est généralement due à un SSL / TLS incompatibilité de version ou de l' échec de la négociation de suite de chiffrement. Cela ne signifie pas que le certificat ssl est « mauvais », il est juste un décalage entre le serveur et le client. Vous pouvez voir exactement où la poignée de main ne parvient pas à l' aide d' un outil comme Wireshark ( plus à ce sujet )

Alors que Wireshark peut être génial de voir où il est défaillant, il ne sera pas vous aider à trouver une solution. Chaque fois que je suis allé sur le débogage handshake_failures dans le passé , j'ai trouvé cet outil particulièrement utile: https://testssl.sh/

Vous pouvez indiquer ce script à l'un de vos sites à défaut d'en savoir plus sur quels protocoles sont disponibles sur cet objectif et ce que vos besoins de clients à l'appui afin d'établir une poignée de main avec succès. Il imprimera également des informations sur le certificat.

Par exemple (ne possédant que deux sections de la sortie de testssl.sh):

./testssl.sh www.google.com
....
 Testing protocols (via sockets except TLS 1.2, SPDY+HTTP2) 

 SSLv2               not offered (OK)
 SSLv3               not offered (OK)
 TLS 1               offered
 TLS 1.1             offered
 TLS 1.2             offered (OK)
 ....
Server Certificate #1
   Signature Algorithm          SHA256 with RSA
   Server key size              RSA 2048 bits
   Common Name (CN)             "www.google.com"
   subjectAltName (SAN)         "www.google.com" 
   Issuer                       "Google Internet Authority G3" ("Google Trust Services" from "US")
   Trust (hostname)             Ok via SAN and CN (works w/o SNI)
   Chain of trust               "/etc/*.pem" cannot be found / not readable
   Certificate Expiration       expires < 60 days (58) (2018-10-30 06:14 --> 2019-01-22 06:14 -0700)
 ....
 Testing all 102 locally available ciphers against the server, ordered by encryption strength 
(Your /usr/bin/openssl cannot show DH/ECDH bits)

Hexcode  Cipher Suite Name (OpenSSL)       KeyExch.  Encryption Bits
------------------------------------------------------------------------
xc030   ECDHE-RSA-AES256-GCM-SHA384       ECDH       AESGCM    256       
xc02c   ECDHE-ECDSA-AES256-GCM-SHA384     ECDH       AESGCM    256       
xc014   ECDHE-RSA-AES256-SHA              ECDH       AES       256       
xc00a   ECDHE-ECDSA-AES256-SHA            ECDH       AES       256       
x9d     AES256-GCM-SHA384                 RSA        AESGCM    256       
x35     AES256-SHA                        RSA        AES       256       
xc02f   ECDHE-RSA-AES128-GCM-SHA256       ECDH       AESGCM    128       
xc02b   ECDHE-ECDSA-AES128-GCM-SHA256     ECDH       AESGCM    128       
xc013   ECDHE-RSA-AES128-SHA              ECDH       AES       128       
xc009   ECDHE-ECDSA-AES128-SHA            ECDH       AES       128       
x9c     AES128-GCM-SHA256                 RSA        AESGCM    128       
x2f     AES128-SHA                        RSA        AES       128       
x0a     DES-CBC3-SHA                      RSA        3DES      168 

Donc , en utilisant cette sortie , nous pouvons voir que si votre client pris en charge uniquement SSLv3, la poignée de main échouerait parce que ce protocole est pas pris en charge par le serveur. L'offre de protocole est peu probable que le problème , mais vous pouvez vérifiez ce que votre client Java prend en charge en obtenant la liste des protocoles activés. Vous pouvez fournir une implémentation surchargée du SSLConnectionSocketFactory de l' extrait de code ci - dessus pour obtenir la liste des permis / protocoles pris en charge et les suites de chiffrement comme suit ( SSLSocket ):

class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory {
    @Override
    protected void prepareSocket(SSLSocket socket) throws IOException {
        System.out.println("Supported Ciphers" + Arrays.toString(socket.getSupportedCipherSuites()));
        System.out.println("Supported Protocols" + Arrays.toString(socket.getSupportedProtocols()));
        System.out.println("Enabled Ciphers" + Arrays.toString(socket.getEnabledCipherSuites()));
        System.out.println("Enabled Protocols" + Arrays.toString(socket.getEnabledProtocols()));
    }
}

Je rencontre souvent handshake_failure quand il y a un échec de la négociation d'une suite de chiffrement. Pour éviter cette erreur, la liste de votre client de suites de chiffrement pris en charge doit contenir au moins un match à une suite de chiffrement de la liste du serveur de suites de chiffrement prises en charge.

Si le serveur requiert des suites de chiffrement AES256 base dont vous avez besoin probablement les extensions de chiffrement Java (JCE). Ces bibliothèques sont la nation limitée et peuvent ne pas être disponibles à quelqu'un en dehors des États-Unis.

Plus sur les restrictions de cryptographie, si vous êtes intéressé: https://crypto.stackexchange.com/questions/20524/why-there-are-limitations-on-using-encryption-with-keys-beyond-certain-length

Articles connexes