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.
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)
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.