473 Stimmen

Urllib und "SSL: CERTIFICATE_VERIFY_FAILED" Fehler

Ich erhalte folgenden Fehler:

Exception in Thread Thread-3:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", Zeile 810, in __bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", Zeile 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/Users/Matthew/Desktop/Skypebot 2.0/bot.py", Zeile 271, in process
info = urllib2.urlopen(req).read()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", Zeile 154, in urlopen
return opener.open(url, data, timeout)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", Zeile 431, in open
response = self._open(req, data)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", Zeile 449, in _open
'_open', req)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", Zeile 409, in _call_chain
result = func(*args)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", Zeile 1240, in https_open
context=self._context)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", Zeile 1197, in do_open
raise URLError(err)
URLError: 

Dies ist der Code, der diesen Fehler verursacht:

if input.startswith("!web"):
    input = input.replace("!web ", "")      
    url = "https://domainsearch.p.mashape.com/index.php?name=" + input
    req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXX' })
    info = urllib2.urlopen(req).read()
    Message.Chat.SendMessage ("" + info)

Die von mir verwendete API erfordert die Verwendung von HTTPS. Wie kann ich sie verifizieren?


Für diese Fehlermeldung <strong>bei der Verwendung von Pip</strong>, siehe <a href="https://stackoverflow.com/questions/25981703">pip install fails with "connection error: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:598)"</a> .

595voto

Craig Glennie Punkte 5215

Dies ist keine Lösung für Ihr spezifisches Problem, aber ich füge es hier hinzu, weil dieser Thread das Top-Ergebnis von Google für "SSL: CERTIFICATE_VERIFY_FAILED" ist und mich auf eine wilde Gänsejagd geführt hat.

Wenn Sie Python 3.6 auf OSX installiert haben und den Fehler "SSL: CERTIFICATE_VERIFY_FAILED" erhalten, wenn Sie versuchen, sich mit einer https://-Website zu verbinden, liegt das wahrscheinlich daran, dass Python 3.6 auf OSX überhaupt keine Zertifikate hat und keine SSL-Verbindungen validieren kann. Dies ist eine Änderung für 3.6 auf OSX und erfordert einen Schritt nach der Installation, der das certifi-Paket von Zertifikaten installiert. Dies ist dokumentiert in der Datei ReadMe.rtf, die Sie unter /Applications/Python\ 3.6/ReadMe.rtf finden können (siehe auch die Datei Conclusion.rtf und das Skript build-installer.py das den macOS-Installer generiert).

Das ReadMe wird Sie auffordern, das Post-Installations-Skript auszuführen unter

/Applications/Python\ 3.10/Install\ Certificates.command (Terminal-App, dieser Befehl alleine sollte das Problem beheben. Stellen Sie sicher, dass Sie den Dateipfad mit Ihrer aktuellen Versionsnummer aktualisieren.)

(Die Quelle dafür ist install_certificates.command), welches:

Die Versionshinweise enthalten weitere Informationen: https://www.python.org/downloads/release/python-360/

In neueren Versionen von Python gibt es mehr Dokumentation darüber:

407voto

Noelkd Punkte 7362

Wenn Sie die Überprüfung nur umgehen möchten, können Sie einen neuen SSLContext erstellen. Standardmäßig verwenden neu erstellte Kontexte CERT_NONE.

Seien Sie vorsichtig damit, wie im Abschnitt 17.3.7.2.1 angegeben

Beim direkten Aufruf des SSLContext-Konstruktors ist CERT_NONE der Standard. Da es den anderen Peer nicht authentifiziert, kann es unsicher sein, insbesondere im Client-Modus, in dem Sie in den meisten Fällen die Authentizität des Servers, mit dem Sie sprechen, sicherstellen möchten. Daher wird im Client-Modus dringend empfohlen, CERT_REQUIRED zu verwenden.

Aber wenn Sie es einfach nur aus irgendeinem Grund zum Laufen bringen wollen, können Sie Folgendes tun, Sie müssen auch import ssl:

input = input.replace("!web ", "")      
url = "https://domainsearch.p.mashape.com/index.php?name=" + input
req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' })
gcontext = ssl.SSLContext()  # Nur für Gangster
info = urllib2.urlopen(req, context=gcontext).read()
Message.Chat.SendMessage ("" + info)

Dies sollte Ihr Problem umgehen, aber Sie lösen nicht wirklich eines der Probleme, aber Sie werden das [SSL: CERTIFICATE_VERIFY_FAILED] nicht sehen, weil Sie das Zertifikat jetzt nicht überprüfen!

Weiter oben, wenn Sie mehr darüber erfahren möchten, warum Sie diese Probleme sehen, sollten Sie sich PEP 476 ansehen.

Dieser PEP schlägt vor, die Überprüfung von X509-Zertifikatsignaturen sowie die Überprüfung des Hostnamens für die Python-HTTP-Clients standardmäßig zu aktivieren, vorbehaltlich einer Abwahl auf Basis eines pro-Aufruf-Basis. Diese Änderung würde auf Python 2.7, Python 3.4 und Python 3.5 angewendet.

Es gibt eine empfohlene Abwahl, die nicht unähnlich meinem obigen Rat ist:

import ssl

# Dies stellt das gleiche Verhalten wie zuvor wieder her.
context = ssl._create_unverified_context()
urllib.urlopen("https://no-valid-cert", context=context)

Es gibt auch eine stark abgeratene Option über Monkeypatching, die man in Python nicht oft sieht:

import ssl

ssl._create_default_https_context = ssl._create_unverified_context

Was die Standardfunktion zur Kontexterstellung mit der Funktion zum Erstellen eines nicht überprüften Kontexts überschreibt.

Bitte beachten Sie dies wie im PEP angegeben:

Diese Richtlinie richtet sich hauptsächlich an Systemadministratoren, die neuere Versionen von Python übernehmen möchten, die diese PEP in Legacy-Umgebungen implementieren, die noch keine Zertifikatüberprüfung für HTTPS-Verbindungen unterstützen. Ein Administrator kann beispielsweise durch Hinzufügen des obigen Monkeypatches zu sitecustomize.py in ihrer Standardbetriebsumgebung für Python auf eine Abwahl verzichten. Anwendungen und Bibliotheken SOLLEN diesen Änderungsprozess NICHT global durchführen (außer vielleicht als Reaktion auf eine von einem Systemadministrator gesteuerte Konfigurationseinstellung).

Wenn Sie einen Artikel darüber lesen möchten, warum das Nichtvalidieren von Zertifikaten in Software schlecht ist, finden Sie ihn

118voto

jnPy Punkte 1329

Um auf Craigs Antwort zu erweitern:

in Python 3.6.1 auf MacOs Sierra

Das Eingeben in das Bash-Terminal hat das Problem gelöst:

pip install certifi
/Applications/Python\ 3.6/Install\ Certificates.command

76voto

Bruno Gabuzomeu Punkte 901

Unter Windows beachtet Python nicht das Systemzertifikat, sondern verwendet sein eigenes Zertifikat, das sich unter ?\lib\site-packages\certifi\cacert.pem befindet.

Die Lösung für Ihr Problem:

  1. Laden Sie das Domänenvalidierungszertifikat als *.crt oder *pem-Datei herunter
  2. Öffnen Sie die Datei im Editor und kopieren Sie deren Inhalt in die Zwischenablage
  3. Finden Sie den Standort Ihres cacert.pem: from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH)
  4. Bearbeiten Sie die Datei cacert.pem und fügen Sie Ihr Domänenvalidierungszertifikat am Ende der Datei ein.
  5. Speichern Sie die Datei und genießen Sie Requests!

68voto

hBy2Py Punkte 1587

Ich hatte ein ähnliches Problem, obwohl ich urllib.request.urlopen in Python 3.4, 3.5 und 3.6 verwendet habe. (Dies ist ein Teil des Python 3-Äquivalents von urllib2, gemäß der Notiz am Anfang der urllib2 Dokumentationsseite von Python 2.)

Meine Lösung bestand darin, pip install certifi auszuführen, um certifi zu installieren, das Folgendes enthält:

... eine sorgfältig kuratierte Sammlung von Stammzertifikaten zur Validierung der Vertrauenswürdigkeit von SSL-Zertifikaten beim Überprüfen der Identität von TLS-Hosts.

Dann habe ich in meinem Code, wo ich zuvor einfach hatte:

import urllib.request as urlrq

resp = urlrq.urlopen('https://example.com/bar/baz.html')

es umgeschrieben zu:

import urllib.request as urlrq
import certifi

resp = urlrq.urlopen('https://example.com/bar/baz.html', cafile=certifi.where())

Wenn ich die urllib2.urlopen Dokumentation richtig verstanden habe, hat auch sie ein cafile Argument. Daher könnte urllib2.urlopen([...], certifi.where()) auch für Python 2.7 funktionieren.


UPDATE (2020-01-01): Ab Python 3.6 wurde das Argument cafile für urlopen als veraltet erklärt, und stattdessen soll das context Argument angegeben werden. Ich habe festgestellt, dass folgendes in 3.5 bis 3.8 gleichermaßen gut funktioniert:

import urllib.request as urlrq
import certifi
import ssl

resp = urlrq.urlopen('https://example.com/bar/baz.html', context=ssl.create_default_context(cafile=certifi.where()))

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X