Fehlermeldung
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate
Auch ausgegeben als
- [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate
Python hängt die Position im C-Quellcode an, etwa „(_ssl.c:1082)“. Nicht zu verwechseln mit „self-signed certificate in certificate chain“: Das bedeutet eine CA-Kette, die in einem nicht vertrauenswürdigen Root-Zertifikat endet. OpenSSL 1.1.1 schreibt „self signed“.
Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)
Was der Fehler bedeutet
Der Server hat ein einzelnes selbstsigniertes Zertifikat vorgelegt (sein Aussteller ist es selbst), das nicht zu den vertrauenswürdigen CAs dieses Kontexts gehört. Es gibt keine CA, die sich nachschlagen ließe, deshalb scheitert OpenSSL auf Tiefe 0. Typisch für Entwicklungsserver, Appliances und frische Installationen; die Abhilfe besteht darin, diesem Zertifikat bewusst zu vertrauen oder es zu ersetzen.
Warum der Fehler auftritt
Ein Entwicklungs- oder Testserver mit generiertem Zertifikat
häufigLokale Server, die mit einem Ad-hoc-Zertifikat gestartet werden (ssl_context="adhoc" in Flask, uvicorn mit generiertem Schlüssel, docker-compose-Stacks), legen ein frisches selbstsigniertes Zertifikat vor, dem kein Client vertraut.
Ein Gerät oder Produkt mit Werkszertifikat
häufigNAS-Systeme, Router, Proxmox, Elasticsearch, Jenkins und viele Hersteller-Appliances starten mit einem selbstsignierten Zertifikat, bis ein Admin ein richtiges installiert.
Ein Proxy liefert sein eingebautes Standardzertifikat aus
gelegentlichIngress-Controller und Reverse Proxys beantworten unbekannte Hostnamen mit einem selbstsignierten Standardzertifikat; das eigentliche Problem ist dann Routing oder SNI.
So behebst du den Fehler
- 1.
Genau diesem Zertifikat für diesen Client vertrauen
Lade das Zertifikat des Servers selbst als cafile. Die Prüfungen von Hostname und Gültigkeitszeitraum bleiben aktiv, und akzeptiert wird nur genau dieses Zertifikat.
python import ssl, urllib.request # Trust exactly this certificate (fetched and fingerprint-checked out of band) ctx = ssl.create_default_context(cafile="api.example.com.pem") urllib.request.urlopen("https://api.example.com:8443/", context=ctx) - 2.
Zertifikat abrufen und Fingerabdruck prüfen
Vergleiche den SHA-256-Fingerabdruck mit dem Wert, den die Konsole des Geräts anzeigt oder den dir sein Admin nennt, bevor du der Datei vertraust.
bash openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \ | openssl x509 -out api.example.com.pem openssl x509 -in api.example.com.pem -noout -fingerprint -sha256 # compare with the server's console - 3.
Entwicklung: stattdessen eine lokale CA verwenden
Mit einer lokalen CA vertraust du einem einzigen Root-Zertifikat und stellst für jeden Entwicklungshost ordentlich signierte Zertifikate aus, sodass kein Client Ausnahmen für einzelne Zertifikate braucht.
bash # Development: one local CA, many certificates (mkcert installs the CA for you) mkcert -install mkcert api.example.test export SSL_CERT_FILE="$(mkcert -CAROOT)/rootCA.pem" - 4.
Vorübergehende Diagnose: Prüfung in einem Test abschalten
check_hostname = False und CERT_NONE schalten jede Prüfung ab und akzeptieren jedes Zertifikat, auch eines, das ein Angreifer vorlegt. Verwende das nur, um zu bestätigen, dass das Vertrauen das einzige Problem ist, und entferne es danach wieder.
python # Temporary diagnostic only: proves trust is the sole problem. Never ship this. import ssl ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE