JWT-Sicherheitsbest Practices | alg none Angriff / Ablauf / Signaturverifizierung
JWT (JSON Web Token) ist der De-facto-Standard für die Authentifizierung in modernen Web-APIs, aber <strong>Implementierungen mit Missverständnis der Spezifikation können leicht Sicherheitslücken erzeugen</strong>. Dieser Artikel erklärt häufig beobachtete Missbrauchsmuster von JWT und Best Practices, um diese zu vermeiden.
JWT-Struktur nochmal durchgehen
JWT ist ein Format, das 3 Base64URL-codierte Zeichenketten mit einem Punkt verbindet.
eyJhbGci... . eyJzdWIi... . SflKxwRJSM...
header payload signature
- <strong>header</strong>: Signaturalgorithmus (<code>alg</code>) und Token-Typ (<code>typ</code>)
- <strong>payload</strong>: JSON-Objekt mit Claims (sub / iss / aud / exp / iat / ...)
- <strong>signature</strong>: HMAC / RSA / ECDSA Signatur für Header und Payload
Der Inhalt des JWT kann mit dem <a href="/ja/tools/jwt/">JWT-Decoder von DevLab</a> überprüft werden. Base64URL ist eine Codierung, keine <strong>Verschlüsselung</strong>, also denken Sie daran, dass der Payload-Inhalt von jedem gelesen werden kann, auch ohne Signaturverifizierung auf dem Server.
Bedrohung 1: Angriff mit alg=none
Die JWT-Spezifikation enthält eine 「signaturlose」 Algorithmusbezeichnung namens <code>"alg": "none"</code>. Wenn ein Angreifer dies nutzt, um die Payload mit einem <code>{"alg":"none"}</code>-Header umzuschreiben, und die Bibliothek sie akzeptiert, wird dies <strong>zu einer kritischen Anfälligkeit, die das Sich-Ausgibt als jeder beliebige Benutzer ermöglicht</strong>.
<strong>Gegenmaßnahmen:</strong>
- <strong>Explicitly eine Whitelist</strong> der zulässigen Algorithmen bei der Validierung angeben
- Als Array übergeben, wie in <code>jwt.verify(token, secret, { algorithms: ['HS256'] })</code>
- Bibliotheken um 2015 waren anfällig, aber die heutigen Hauptbibliotheken haben Gegenmaßnahmen getroffen. Verwenden Sie jedoch die neueste Version, es sei denn, Sie erstellen Ihre eigene
// ✗ 悪い例 (アルゴリズム未指定 = ライブラリが alg ヘッダを信頼)
jwt.verify(token, secret);
// ✓ 良い例 (アルゴリズムを固定)
jwt.verify(token, secret, { algorithms: ['HS256'] });
Bedrohung 2: Schlüsselverwechslungsangriff (key confusion)
Dies ist ein Angriff, bei dem ein Angreifer, der den öffentlichen RSA-Schlüssel hat, <strong>den Algorithmus von RS256 zu HS256 ändert</strong>, um den öffentlichen Schlüssel als 「geheimen Schlüssel」 zu behandeln. Wenn die JWT-Bibliothek <code>alg</code> vertraut und die Verifizierungsfunktion auswählt, kann ein falsches Token mit HMAC-Signatur unter Verwendung des öffentlichen Schlüssels durchgehen.
<strong>Gegenmaßnahmen:</strong> Der Algorithmus muss auf der Verifikationsseite immer fixiert werden (gleiche Gegenmaßnahme wie Bedrohung 1). Unterscheiden Sie darüber hinaus explizit den Schlüsseltyp:
- Bei HS256 mit <code>Buffer</code> übergeben
- Für RS256 öffentlichen Schlüssel im PEM-Format übergeben
Bedrohung 3: Nicht validierte Ablaufzeit / Token ohne Gültigkeit
Der <code>exp</code>-Anspruch von JWT zeigt das Ablaufdatum in UNIX-Sekunden an, wird aber <strong>bei der Validierung oft ignoriert</strong>. Wenn ein einmal ausgegebenes Token unbegrenzt verwendet werden kann, hört der Schaden bei einem Datenleck nicht auf.
<strong>Gegenmaßnahmen:</strong>
- <code>exp</code> kurz bei der Ausstellung festlegen (Zugriffstoken sollten 15 Minuten bis 1 Stunde als Richtlinie sein)
- Immer <code>exp</code> während der Validierung überprüfen (große Bibliotheken tun dies automatisch)
- Wenn eine Langzeitsitzung erforderlich ist, verwenden Sie das Refresh-Token-Muster (kurzlebiger Zugriffstoken + langlebiger Refresh-Token + serverseitige Blacklist)
Bedrohung 4: Vertrauliche Informationen in JWT einfügen
Das JWT-Payload ist nur Base64-Codierung und kann von jedem dekodiert werden. Implementierungen, die <strong>Passwörter oder Kreditkartennummern in das Payload einfügen</strong>, ohne dies zu wissen, sind immer noch üblich.
<strong>Gegenmaßnahmen:</strong>
- Payload sollte nur minimale Identifizierungsinformationen enthalten (sub / user_id / role)
- Vertrauliche Informationen in der serverseitigen Datenbank ablegen und über die JWT mit user_id abrufen
- Wenn Sie unbedingt vertrauliche Informationen mit JWT senden müssen, verwenden Sie <strong>JWE</strong> (verschlüsseltes JWT)
Bedrohung 5: Abmeldung (Logout) nicht möglich
Wenn das JWT zustandslos ausgegeben wird, kann es nicht widerrufen werden. Selbst wenn sich der Benutzer abmeldet, kann das Token "bis zum Ablauf verwendet werden", da der Server keine Token-Informationen hat. Auch nach einer Passwortänderung bleibt das ausgegebene JWT gültig.
<strong>Gegenmaßnahmen:</strong>
- Minimieren Sie das Schadensrisikofenster mit kurzem <code>exp</code> (15 Minuten oder weniger)
- Registrieren Sie beim Logout die <code>jti</code> (JWT ID) in der serverseitigen <strong>Sperrliste (denylist)</strong> und gleichen Sie während der Validierung ab
- Bei kritischen Ereignissen (Passwortänderung・Berechtigungsänderung) speichern Sie <code>token_version</code> im Benutzerdatensatz und überprüfen Sie die Übereinstimmung bei der Validierung
Bedrohung 6: Schwaches Geheimnis
Wenn das HS256-Geheimnis zu kurz ist, kann es durch Brute-Force entschlüsselt werden. Besonders Strings wie <code>"secret"</code> und <code>"password123"</code> sind anfällig.
<strong>Gegenmaßnahmen:</strong>
- HS256 muss einen Zufallswert von mindestens <strong>256 Bit (32 Bytes)</strong> verwenden
- Generieren mit <code>openssl rand -base64 32</code> oder <a href="/ja/tools/password/">Passwortgenerator-Tool</a>
- Committen Sie Geheimnisse niemals in Git. Verwalten Sie sie mit Umgebungsvariablen und Secrets Manager
Zusammenfassung der Best Practices
- Algorithmus auf der Verifizierungsseite festlegen (<code>algorithms: ['HS256']</code>)
- Das HS256-Geheimnis muss 256 Bit oder mehr sein, für RS256 RSA mit 2048 Bit oder mehr
- Das <code>exp</code> des Zugriffstokens beträgt 15 Minuten bis 1 Stunde
- Implementieren Sie lange Sitzungen mit dem Refresh-Token-Muster
- Keine sensiblen Informationen im Payload (Base64 ist keine Verschlüsselung)
- Registrieren Sie die <code>jti</code> in der Sperrliste beim Logout
- Geheimnisse müssen mit Umgebungsvariablen und Secrets Manager verwaltet werden, niemals committen
- Speichern Sie JWT auf der Clientseite in einem HttpOnly-Cookie statt in localStorage (XSS-Schutz)
Hilfswerkzeuge zum Debuggen
- <a href="/ja/tools/jwt/">JWT-Decoder</a>: Visualisiert header / payload / signature, zeigt Bedeutung jedes Claims mit Erklärung an
- <a href="/ja/tools/jwt-sign/">JWT-Generierungs- und Signierwerkzeug</a>: Signieren Sie im Browser mit Web Crypto API mit HS256 / HS384 / HS512. Praktisch zum Generieren von Test-Token
- <a href="/ja/tools/password/">Passwort-Generator</a>: Kann zum Generieren von Geheimnissen verwendet werden
Zusammenfassung
JWT ist ein praktisches Authentifizierungstoken, wenn es richtig verwendet wird, aber wenn Sie die Fallstricke der Spezifikation und Angriffsmuster nicht kennen, führt dies zu Anfälligkeiten im Produktionssystem. Es ist wichtig, die 6 in diesem Artikel beschriebenen Bedrohungen und Gegenmaßnahmen zu beherrschen und die neueste Version der JWT-Bibliothek zu verwenden. Wir empfehlen, die Implementierung regelmäßig zu überprüfen und Sicherheitshinweise zu verfolgen.