webentwicklung-frage-antwort-db.com.de

SSL-Fehler unter Windows mit Python-Anforderungen

Entschuldigung für den sehr langen Beitrag, aber ich versuche wirklich gründlich zu sein ...

Ich habe eine eigene Website, die als Brücke dient, um Daten zwischen verschiedenen Umgebungsmodellen auszutauschen, die von Remote-Servern aus betrieben werden und auf verschiedenen Betriebssystemen (Linux, MacOS und Windows) laufen. Grundsätzlich kann jeder Server Datendateien auf die Website hochladen/herunterladen, und die Dateien werden dann zur weiteren Verarbeitung mit einem anderen Modell auf einem anderen Server verwendet.

Die Websites verfügen über einen grundlegenden Schutz (IP-Filterung, Kennwort und SSL mit LetsEncrypt-Zertifikaten). Alle Remote-Server können über eine von uns erstellte einfache Weboberfläche auf die Site zugreifen und Daten hochladen/herunterladen.

Jetzt versuchen wir, einen Teil des Austauschs mit einem einfachen Python-Dämon (2.7) (basierend auf dem Requests-Modul) zu automatisieren. Der Daemon überwacht bestimmte Ordner und lädt den Inhalt auf die Website hoch.

Der Daemon funktioniert einwandfrei auf allen Remote-Servern, außer auf einem Windows 7 Enterprise 64bit. Auf diesem Server sind Python 2.7.13 und die folgenden Pakete installiert: DateTime (4.1.1), psutil (5.2.0), pytz (2016.10), Anforderungen (2.13.0), zope.interface (4.3.3).

Von diesem Server aus funktioniert die SSL-Verbindung über einen Webbrowser einwandfrei. Der Dämon gibt jedoch immer Folgendes zurück: 

raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)

Das haben wir bisher ausprobiert:

  • einstellung verify = false. Das funktioniert gut, aber wir können es nicht in unserer endgültigen Produktionsumgebung einsetzen.
  • kopieren des Zertifikats von einem anderen Server, auf dem der Dämon funktioniert, und Einstellen von verify = (Name der Zertifikatsdatei) (kein Erfolg)
  • setzen des Benutzeragenten auf genau dieselbe Zeichenfolge, die wir von der Windows-Maschine auf der Website erhalten, wenn die Verbindung mit einem Webbrowser hergestellt wird (kein Erfolg)

Welche andere Einstellung sollten wir auf dem Windows-Server betrachten, um das Problem zu lösen? Kann es eine Firewall-Einstellung sein, durch die der Browser die SSL-Verbindung irgendwie durchlässt, der Python-Dämon jedoch blockiert wird?

UPDATE
Die Organisation, die den Windows-Remoteserver ausführt, auf dem der Fehler aufgetreten ist, ersetzt alle SSL-Zertifikate auf Proxy-Ebene.
Ihre IT-Mitarbeiter lösten unser Problem, indem sie die URL unserer Website zur Liste der "Pass Through" -Seiten in ihren Proxy-Einstellungen hinzufügten. 

Das funktioniert und ist vorerst in Ordnung. Ich frage mich jedoch, ob wir die Zertifikatsubstitution direkt in Python hätten erledigen können ...

6
user6357781

Es ist möglich, die Bibliothek Requests zu verwenden, um das eingebaute Modul ssl von Python zu verwenden, um den SSL-Teil der HTTP-Verbindung herzustellen. Dies ist machbar, da die von Requests verwendeten urllib3-Utils die Übergabe eines Python SSLContext in diese zulassen.

Beachten Sie jedoch, dass dies möglicherweise davon abhängt, dass die erforderlichen Zertifikate bereits in den Trust Store geladen wurden, basierend auf einem vorherigen Windows-Zugriff (siehe diesen Kommentar ).

Es folgt ein Beispielcode (dies erfordert eine aktuelle Version von Requests; es funktioniert mit 2.18.4):

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context

class SSLContextAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context()
        kwargs['ssl_context'] = context
        context.load_default_certs() # this loads the OS defaults on Windows
        return super(SSLContextAdapter, self).init_poolmanager(*args, **kwargs)

s = requests.Session()
adapter = SSLContextAdapter()
s.mount('https://myinternalsite', adapter)
response = s.get('https://myinternalsite')
10
David Fraser

Requests verwendet Ihren Windows-Stammzertifizierungsstellenspeicher nicht wie Ihr Browser.

Aus den Dokumenten: Standardmäßig bündelt Requests eine Reihe von Stammzertifizierungsstellen, denen es vertraut, die aus dem Mozilla-Vertrauensspeicher stammen. Diese werden jedoch nur einmal für jede Anforderungsversion aktualisiert. 

Diese Liste vertrauenswürdiger Zertifizierungsstellen kann auch über die Umgebungsvariable REQUESTS_CA_BUNDLE angegeben werden.

Sie können das buchstäblich tun:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

Oder Sie können certifi verwenden, wenn Ihr CA-Zertifikat von einer öffentlichen Entität signiert ist. 

1
Artagel