web-dev-qa-db-fra.com

Pourquoi Ruby est-il incapable de vérifier un certificat SSL?

C'est la première fois que j'essaie d'utiliser la bibliothèque XMLRPC :: Client pour interagir avec une API distante et je continue à recevoir cette erreur:

warning: peer certificate won't be verified in this SSL session

En cherchant, j'ai trouvé des tas de gens qui ont eu cette erreur. Habituellement, c'est avec des certificats auto-signés et ils veulent juste que ça s'en aille, alors ils font quelque chose de sale, comme monkey patch, comme XMLRPC :: Client ouvre sa session http.

J'ai d'abord supposé que c'était simplement le client qui se souciait peu de savoir si le certificat était valide ou non, alors j'ai poursuivi ma recherche et suis tombé sur ce bijou . Il oblige simplement à vérifier tous les certificats SSL et génère une erreur si cela n’est pas possible. C'était exactement ce que je voulais. Je l'ai inclus, j'ai relancé le code et maintenant je reçois ceci:

OpenSSL:SSL::SSLError:
  SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B:
  certificate verify failed

Bien sûr! Le certificat est mauvais! Mais je vérifie juste pour m'assurer que le s_client intégré à openssl ressemble à ceci:

openssl s_client -connect sub.example.com:443

et qu'est-ce que je reçois:

CONNECTED(00000003)
---
Certificate chain
<snip>
Verify return code: 0 (ok)

Alors maintenant, nous arrivons à ma question. OpenSSL (la version en ligne de commande) dit que le certificat est bon. OpenSSL (la bibliothèque Ruby) n'est pas d'accord. Tous mes navigateurs Web disent que le certificat est bon.

Quelques détails supplémentaires qui pourraient être utiles. Le certificat est un caractère générique mais est valide pour le domaine. Le s_client openssl a été exécuté sur la même machine secondes que le code Ruby. C'est Ruby 1.8.7 p357 qui est installé avec RVM.

Ruby utilise-t-il autre chose que le bundle d'AC fourni par le système d'exploitation hôte? Existe-t-il un moyen de dire à Ruby d'utiliser un bundle d'autorité de certification spécifique ou celui du système?

53
Sam Stelfox

Si vous souhaitez uniquement que Ruby se comporte de la même manière qu'OpenSSL s_client ou que votre navigateur le fait, vous pouvez passer à la toute dernière section. Je vais couvrir les petits caractères dans ce qui suit.

Par défaut, le OpenSSL::X509::Store utilisé pour établir la connexion n'utilise aucun certificat approuvé. En fonction de votre connaissance du domaine d'application, vous alimentez généralement une instance de X509::Store avec le ou les certificats de confiance pertinents pour votre application. Il y a plusieurs options pour cela:

  • Store # add_file prend le chemin d'un certificat codé PEM/DER
  • Store # add_cert prend une instance de X509 :: Certificate
  • Store # add_path prend un chemin vers un répertoire où se trouvent des certificats sécurisés 

L'approche "navigateur"

Cela contraste avec l'approche adoptée par les navigateurs, Java (cacerts) ou Windows avec son propre magasin interne de certificats de confiance. Le logiciel y est pré-équipé d’un ensemble de certificats de confiance qui est considéré comme "bon" par l’opinion du fournisseur du logiciel. En règle générale, ce n'est pas une mauvaise idée, mais si vous examinez ces ensembles, vous remarquerez bientôt qu'il y a trop de certificats. Un individu ne peut pas vraiment dire si tous de ces certificats doivent faire l’objet d’une confiance aveugle ou non. 

L'approche rubis

Les exigences de votre application Ruby typique sont en revanche très différentes de celles d'un navigateur. Un navigateur doit pouvoir vous permettre de naviguer vers n'importe quel site Web "légitime" fourni avec un certificat TLS et desservi via https. Cependant, dans une application Ruby typique, vous ne devrez traiter que quelques services utilisant TLS ou nécessitant une validation des certificats. 

Et il y a l'avantage de l'approche Ruby: bien qu'elle nécessite davantage de travail manuel, vous obtiendrez une solution personnalisée qui confie avec précision les certificats auxquels elle doit faire confiance dans le contexte de votre application. Ceci est fastidieux, mais la sécurité est beaucoup plus élevée de cette façon, car vous exposez beaucoup moins de surface d’attaque. Prenons les événements récents: si vous n'avez jamais eu à inclure DigiNotar ou toute autre racine compromise dans votre jeu de relations de confiance, il est impossible que de telles violations vous affectent.

Cependant, comme vous l'avez déjà remarqué, l'inconvénient est que, par défaut, si vous n'ajoutez pas activement de certificats de confiance, l'extension OpenSSL ne pourra pas valider le certificat aucun homologue. Pour que les choses fonctionnent, vous devez configurer la configuration manuellement. 

Cet inconvénient a conduit à de nombreuses mesures douteuses pour le contourner, le pire de toutes étant de définir globalement OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE. S'il vous plaît ne faites pas cela. Nous avons même fait des blagues sur l'ajout de code permettant à votre application de planter de manière aléatoire si nous rencontrons ce hack :)

Si la configuration manuelle de la confiance vous semble trop compliquée, je vous proposerai une alternative simple qui permet à l'extension OpenSSL de se comporter exactement comme les commandes OpenSSL CLI telles que s_client.

Pourquoi s_client peut vérifier le certificat

OpenSSL utilise une approche similaire pour les navigateurs et Windows. Une installation typique mettra un ensemble de certificats de confiance quelque part sur votre disque dur (quelque chose comme /etc/ssl/certs/ca-bundle.crt), qui servira de jeu par défaut de certificats de confiance. C'est là que s_client apparaît lorsqu'il doit vérifier des certificats homologues et c'est pourquoi votre expérience a réussi.

Faire en sorte que Ruby agisse comme un client

Si vous souhaitez toujours bénéficier du même confort lors de la validation de certificats avec Ruby, vous pouvez lui indiquer d'utiliser le groupe OpenSSL de certificats de confiance, s'il est disponible sur votre système, en appelant OpenSSL::X509::Store#set_default_paths. Des informations supplémentaires peuvent être trouvées ici . Pour utiliser ceci avec XMLRPC::Client, assurez-vous simplement que set_default_paths est appelé sur le X509::Store utilisé.

110
emboss

Si vous avez un fichier ca-certificates, procédez comme suit:

http.ca_file = <YOUR CA-CERT FILE PATH>
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 5
0
Guihen