Fehlermeldung
Signature verification failed
PyJWT (Python) — jwt.exceptions.InvalidSignatureError
Was der Fehler bedeutet
PyJWT hat die Struktur des Tokens dekodiert und die Signaturprüfung ausgeführt, und diese ist fehlgeschlagen: Die Signatur passt nicht zu Schlüssel und Payload. InvalidSignatureError ist eine Unterklasse von DecodeError, deshalb kann ein zu breit gefasstes except DecodeError den Fehler fälschlich als Parsing-Problem einordnen – tatsächlich passen Schlüssel und Inhalt nicht zusammen. Bei ES256-Tokens kommt eine Feinheit hinzu: Die JWS-Signatur muss in der rohen 64-Byte-Form r‖s vorliegen, deshalb scheitern hier Tokens von selbst gebauten Signierern, die ASN.1 DER ausgegeben haben, selbst wenn der Schlüssel stimmt.
Warum der Fehler auftritt
Ein anderer Schlüssel als beim Aussteller
häufigEin rotiertes Schlüsselpaar, bei dem die prüfende Seite den alten öffentlichen Schlüssel behalten hat, ein per Copy-and-paste übernommenes falsches PEM oder zwei Dienste, die unterschiedliche Secret-Versionen aus dem Secret Manager lesen. Bei Ausstellern mit JWKS hat ein nicht passender kid dieselbe Wirkung.
Ein selbst gebauter Signierer hat eine falsche Signatur erzeugt
gelegentlichNeben DER statt rohem r‖s erzeugt auch ein selbst gebauter Signierer, der unter einem ES256-Header mit SHA-384 hasht oder das JSON statt des base64url-Texts header.payload signiert, eine formal korrekte Signatur, die die Prüfung nie besteht. Ein Schlüssel, der auf dem Weg durch die Konfiguration beschädigt wurde, landet nicht hier: Ein PEM mit wörtlichen \n-Sequenzen lässt sich gar nicht erst laden und scheitert mit „Unable to load PEM file“, und Anführungszeichen oder Einrückungen um ein intaktes PEM werden toleriert.
Token nach dem Signieren verändert
gelegentlichMiddleware, die das JSON der Payload neu serialisiert oder auch nur ein einziges Zeichen ändert, verändert die signierten Bytes. Die Signatur deckt genau den base64url-Text ab – kosmetische Änderungen sind nicht kosmetisch. (Hinzugefügtes base64-Padding wird schon früher als „Invalid payload padding“ abgelehnt, ein abgeschnittenes Token als „Not enough segments“.)
So behebst du den Fehler
- 1.
Fingerabdruck des Schlüssels auf beiden Seiten bilden
Gib einen SHA-256-Fingerabdruck des öffentlichen Schlüssels aus, den die prüfende Seite geladen hat, und vergleiche ihn mit dem des Ausstellers. Ein Unterschied beendet die Suche; stimmen beide überein, liegt das Problem stattdessen in den Bytes des Tokens.
python import hashlib from cryptography.hazmat.primitives import serialization public_key = serialization.load_pem_public_key(pem_bytes) # the key the verifier uses spki = public_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo) print(hashlib.sha256(spki).hexdigest()) # compare with the issuer's - 2.
kid prüfen, bevor du eine Beschädigung vermutest
Lies den ungeprüften Header und stelle sicher, dass du mit dem Schlüssel prüfst, den das Token nennt. Hat der Aussteller mehrere Schlüssel, ermittle den passenden über den kid mit PyJWKClient.
python import jwt header = jwt.get_unverified_header(token) print(header) # {'alg': 'ES256', 'kid': '...'} from jwt import PyJWKClient key = PyJWKClient("https://issuer.example/.well-known/jwks.json") \ .get_signing_key_from_jwt(token).key payload = jwt.decode(token, key, algorithms=["ES256"], audience="api://orders")