Fehlermeldung
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure
Auch ausgegeben als
- [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure
Der Reason-Code bleibt SSLV3_ALERT_HANDSHAKE_FAILURE, der Text hängt aber von OpenSSL ab: „ssl/tls alert handshake failure“ ab OpenSSL 3.3, „sslv3 alert handshake failure“ in älteren Versionen. Danach folgt eine Quellcode-Position wie „(_ssl.c:1082)“.
Python ssl module (OpenSSL) — ssl.SSLError, TLS alert 40 (handshake_failure) from the server
Was der Fehler bedeutet
Der Server hat den Handshake mit dem TLS-Alert 40 (handshake_failure) abgebrochen. Er hat im ClientHello von Python keine akzeptablen Parameter gefunden oder ein Client-Zertifikat verlangt, das nicht vorgelegt wurde. Der Alert selbst enthält keine Details, deshalb findest du die Ursache nur, indem du vergleichst, was jede Seite unterstützt, oder indem du das Log des Servers liest.
Warum der Fehler auftritt
Keine gemeinsame Cipher Suite
häufigSeit Python 3.10 bietet der Standardkontext keine Suites ohne Forward Secrecy und keine mit SHA-1-MACs an, und zwar bei OpenSSL-Sicherheitsniveau 2. Veraltete Server, die auf Suites mit RSA-Schlüsselaustausch, CBC-SHA oder 3DES beschränkt sind, haben mit diesem Kontext nichts gemeinsam.
Der Server verlangt ein Client-Zertifikat
häufigMutual-TLS-Endpunkte (Banken- und B2B-APIs, interne Dienste) beantworten unter TLS 1.2 einen Handshake ohne Client-Zertifikat mit diesem Alert.
SNI fehlt oder ist auf dem Server nicht konfiguriert
gelegentlichVerbindest du dich per IP ohne server_hostname oder mit einem Namen, den das CDN oder der Proxy nicht bedient, brechen manche Server mit handshake_failure ab.
So behebst du den Fehler
- 1.
Cipher-Listen vergleichen
Gib aus, was dieses Python anbietet, und vergleiche es mit der Liste des Servers (zum Beispiel aus nmap --script ssl-enum-ciphers). Gibt es keine Überschneidung, muss der Server aktualisiert werden.
python import ssl ctx = ssl.create_default_context() print(sorted(c["name"] for c in ctx.get_ciphers())) # what this Python offers (TLS 1.2 names) - 2.
Client-Zertifikat vorlegen
Lade bei mTLS-APIs das Client-Zertifikat und den Schlüssel mit load_cert_chain() in den Kontext; requests nimmt cert=("client.pem", "client.key") entgegen.
python import ssl, urllib.request ctx = ssl.create_default_context() ctx.load_cert_chain(certfile="client.pem", keyfile="client.key") # mutual TLS urllib.request.urlopen("https://mtls.example.com/", context=ctx) - 3.
Eigener Server: aktuelle Suites anbieten
TLS 1.3 und zusätzlich TLS 1.2 mit ECDHE und AES-GCM oder ChaCha20-Poly1305 akzeptiert jeder Client, der noch gepflegt wird.
text # Server side: offer TLS 1.3 and TLS 1.2 ECDHE + AEAD suites ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;