web-dev-qa-db-fra.com

échec de la vérification du certificat: impossible d'obtenir le certificat de l'émetteur local

J'essaie d'obtenir des données du Web à l'aide de python. J'ai importé le paquet urllib.request pour cela mais lors de l'exécution, j'obtiens une erreur:

certificate verify failed: unable to get local issuer certificate (_ssl.c:1045)

Lorsque j'ai changé l'URL en "http", je suis en mesure d'obtenir des données. Mais, je crois, cela évite de vérifier le certificat SSL.

J'ai donc vérifié sur Internet et trouvé une solution: Exécuter /Applications/Python\ 3.7/Install\ Certificates.command

Cela a résolu mon problème. Mais je n'ai aucune connaissance sur SSL et les goûts. Pouvez-vous m'aider à comprendre ce que cela a réellement fait pour résoudre mon problème?.

Si possible, merci de me recommander toute bonne ressource pour en savoir plus sur la sécurité et les certificats. Je suis nouveau à cela.

Merci!

Remarque: j'ai parcouru le lien - openssl, python demande l'erreur: "la vérification du certificat a échoué"

Ma question diffère de celle de link car, je veux savoir ce qui se passe réellement lorsque j'installe le package certifi ou exécute Install\ Certificates.command pour corriger l'erreur. J'ai une mauvaise compréhension des valeurs mobilières.

20
Biswajit Paul

Je parle du même problème sous OSX, alors que mon code fonctionnait parfaitement sous Linux, et vous avez répondu à cette question!

Après avoir inspecté le fichier que vous avez pointé sur /Applications/Python 3.7/Install Certificates.command, il s’est avéré que cette commande remplaçait les certificats racine de l’installation par défaut Python par ceux fournis avec le package certifi.

certifi est un ensemble de certificats racine. Chaque certificat SSL repose sur une chaîne de confiance: vous faites confiance à un certificat spécifique parce que vous faites confiance au parent de ce certificat, pour lequel vous faites confiance au parent, etc. À un moment donné, il n'y a pas de "parent" et il s'agit de certificats "racine". Pour ceux-là, il n’ya pas d’autre solution que de regrouper des certificats racine de confiance (généralement de grandes sociétés de confiance telles que "DigiCert").

Vous pouvez par exemple voir les certificats racine dans les paramètres de sécurité de votre navigateur (par exemple pour Firefox-> Préférences-> Confidentialité et sécurité-> Afficher les certificats-> Autorités).

Pour revenir au problème initial et avant d'exécuter le fichier .command, son exécution me renvoie une liste vide sur une nouvelle installation:

import os
import ssl                                        
openssl_dir, openssl_cafile = os.path.split(      
    ssl.get_default_verify_paths().openssl_cafile)
# no content in this folder
os.listdir(openssl_dir)
# non existent file
print(os.path.exists(openssl_cafile))

Cela signifie qu'il n'y a pas d'autorité de certification par défaut pour l'installation Python sur OSX. Une valeur par défaut possible est exactement celle fournie par le package certifi.

Après cela, vous pouvez simplement créer un contexte SSL qui a la valeur par défaut appropriée comme suit (certifi.where() donne l'emplacement d'une autorité de certification):

import platform
# ...

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.check_hostname = True
ssl_context.load_default_certs()

if platform.system().lower() == 'darwin':
    import certifi
    ssl_context.load_verify_locations(
        cafile=os.path.relpath(certifi.where()),
        capath=None,
        cadata=None)

et faire une demande à un url de python comme ceci:

import urllib
# previous context
https_handler = urllib.request.HTTPSHandler(context=ssl_context)

opener = urllib.request.build_opener(https_handler)
ret = opener.open(url, timeout=2)
4
Raffi

J'ai eu l'erreur avec conda sur linux. Ma solution était simple.

conda install -c conda-forge certifi

J'ai dû utiliser le conda forge car le certificat par défaut semble avoir des problèmes.

0
netskink