Skip to content

How-to: Bearer-Token-Middleware (JWT-Auth-Randfälle)

FT-Referenz: FT273 (NENE2-FT/authlog) — BearerTokenMiddleware JWT-Auth: alg=none-Ablehnung, Signatur-Manipulations-Erkennung, exp/nbf-Durchsetzung, WWW-Authenticate-Header, Sub-basierte Datenisolation, IDOR → 404, 18 Tests / 26 Assertions bestanden.

VULN-Bewertung: V-01 bis V-10 am Ende dieses Dokuments.

Demonstriert die Verwendung von NENE2's BearerTokenMiddleware + LocalBearerTokenVerifier (HMAC-HS256) zum Schutz von Routen. Alle JWT-Validierungs-Randfälle werden von der Middleware behandelt; Controller empfangen dekodierte Claims nur über nene2.auth.claims.


Einrichtung

php
$verifier        = new LocalBearerTokenVerifier($secret); // env: NENE2_LOCAL_JWT_SECRET
$bearerMiddleware = new BearerTokenMiddleware($problems, $verifier);

$app = (new RuntimeApplicationFactory(
    $psr17, $psr17,
    routeRegistrars: [static fn (Router $r) => $registrar->register($r)],
    authMiddleware:  $bearerMiddleware,
))->create();

Die Middleware setzt nene2.auth.claims auf den Request, bevor ein Route-Handler ausgeführt wird. Bei fehlgeschlagener Validierung gibt sie 401 mit WWW-Authenticate: Bearer zurück, bevor der Handler aufgerufen wird.


Claims in einem Controller extrahieren

php
private function resolveOwnerId(ServerRequestInterface $request): string
{
    /** @var array<string, mixed> $claims */
    $claims = $request->getAttribute('nene2.auth.claims') ?? [];
    return (string) ($claims['sub'] ?? '');
}

Der sub-Claim ist die kanonische Benutzeridentität. Ihn als owner_id zu verwenden stellt die Datenisolation pro Benutzer ohne zusätzliche Abfragen sicher.


WWW-Authenticate-Header

Bei 401 sendet die Middleware WWW-Authenticate: Bearer realm="api". Bei abgelaufenen Tokens enthält der Header error="invalid_token":

WWW-Authenticate: Bearer realm="api", error="invalid_token", error_description="..."

RFC-6750-Konformität ermöglicht es Clients, "kein Token" von "schlechtes Token" zu unterscheiden.


Schwachstellenbewertung

V-01 — alg=none-Algorithm-Substitution ✅ SAFE

Risiko: Ein Angreifer erstellt ein JWT mit "alg":"none" und einem unsignierten Payload, der sub: admin beansprucht. Befund: SAFE — LocalBearerTokenVerifier akzeptiert nur HMAC-HS256. alg=none-Tokens werden bei der Signaturverifizierung abgelehnt; der Test testWrongAlgorithmHeaderReturns401 bestätigt 401.


V-02 — Signatur-Manipulation ✅ SAFE

Risiko: Ein Angreifer fängt ein gültiges JWT ab und ändert den Payload (z. B. sub auf admin), behält aber Header und Originalsignatur bei. Befund: SAFE — Die HMAC-HS256-Signatur deckt header.payload ab. Jede Änderung macht den MAC ungültig; testTamperedPayloadReturns401 bestätigt 401.


V-03 — Abgelaufenes Token wiederverwenden ✅ SAFE

Risiko: Ein abgelaufenes Token wird wiederholt, nachdem die Session ungültig sein sollte. Befund: SAFE — Der exp-Claim wird validiert; Tokens mit exp < time() werden abgelehnt. testExpiredTokenReturns401 bestätigt 401 mit invalid_token im WWW-Authenticate.


V-04 — Not-before (nbf) umgehen ✅ SAFE

Risiko: Ein Token mit zukünftigem nbf (noch nicht gültig) wird vor seiner Aktivierungszeit verwendet. Befund: SAFE — nbf wird durchgesetzt; testNbfInFutureReturns401 bestätigt 401.


V-05 — Falsches Authorization-Schema ✅ SAFE

Risiko: Ein Angreifer sendet Authorization: Basic dXNlcjpwYXNz oder lässt das Bearer -Präfix weg. Befund: SAFE — Die Middleware akzeptiert nur Tokens mit Bearer -Präfix. Basic und bare Token-Strings geben beide 401 zurück.


V-06 — Fehlerhafte Token-Struktur ✅ SAFE

Risiko: Ein Angreifer sendet Tokens mit 2 Teilen, 4 Teilen, ungültigem Base64-Payload oder zufälligen Strings, um die Fehlerbehandlung zu sondieren. Befund: SAFE — Alle fehlerhaften Varianten geben 401 zurück. Tokens ohne 3 Teile und ungültiges Base64 werden vor jeder Claim-Extraktion abgelehnt.


V-07 — Falsches Signatur-Secret ✅ SAFE

Risiko: Ein Angreifer mit Kenntnis des JWT-Formats signiert ein Token mit einem anderen Secret. Befund: SAFE — Die HMAC-Verifizierung schlägt fehl, wenn das Secret abweicht; testWrongSecretSignatureReturns401 bestätigt 401.


V-08 — IDOR: Datenzugriff auf andere Benutzer ✅ SAFE

Risiko: Benutzer A versucht, die Daten von Benutzer B zu lesen, indem er die Eintrags-ID kennt oder errät. Befund: SAFE — findByIdAndOwner($id, $ownerId) begrenzt die Suche auf den JWT-sub. Eine cross-user-Anfrage gibt 404 zurück (nicht 403), um nicht zu verraten, dass der Eintrag existiert.


V-09 — Datenisolation pro Benutzer ✅ SAFE

Risiko: Schreibvorgänge von Benutzer A sind für Benutzer B sichtbar. Befund: SAFE — Alle Lesevorgänge sind nach owner_id = sub begrenzt. testEntriesAreIsolatedByToken verifiziert, dass Alices und Bobs Einträge vollständig getrennt sind.


V-10 — Token ohne exp-Claim ✅ SAFE (akzeptabel)

Risiko: Ein Token ohne exp-Claim wird ausgestellt und wird damit effektiv nicht ablaufend. Befund: SAFE (by design) — LocalBearerTokenVerifier validiert exp nur, wenn der Claim vorhanden ist. Tokens ohne exp werden akzeptiert. Dies ist ein bewusster Kompromiss für Service-to-Service-Szenarien; Produktions-Deployments sollten exp über einen strengeren Verifier durchsetzen, wenn nötig.


VULN-Zusammenfassung

IDSchwachstelleBefund
V-01alg=none-Algorithm-Substitution✅ SAFE
V-02Signatur-Manipulation✅ SAFE
V-03Abgelaufenes Token wiederverwenden✅ SAFE
V-04Not-before (nbf) umgehen✅ SAFE
V-05Falsches Authorization-Schema✅ SAFE
V-06Fehlerhafte Token-Struktur✅ SAFE
V-07Falsches Signatur-Secret✅ SAFE
V-08IDOR-Datenzugriff auf andere Benutzer✅ SAFE
V-09Datenisolation pro Benutzer✅ SAFE
V-10Token ohne exp-Claim✅ SAFE (by design)

10 SAFE, 0 EXPOSED Keine kritischen Schwachstellen. BearerTokenMiddleware behandelt alle Standard-JWT-Angriffsvektoren; Anwendungscode muss nur den sub-Claim für das Eigentümer-Scoping verwenden.


Was man NICHT tun sollte

Anti-MusterRisiko
alg=none-Tokens akzeptierenAngreifer kann jede Identität fälschen, indem er die Signatur weglässt
exp-Validierung überspringenGestohlene Tokens bleiben unbegrenzt gültig
403 bei IDOR zurückgebenVerrät, dass die Ressource existiert und jemandem gehört
X-User-Id-Header statt JWT-sub verwendenHeader ist trivial fälschbar; JWT-Claim ist kryptografisch gebunden
Signing-Secret umgebungsübergreifend teilenEin Dev-Env-Leak kompromittiert Produktions-Tokens
RS256-Schlüssel kleiner als 2048 Bit verwendenAnfällig für Faktorisierungsangriffe

Veröffentlicht unter der MIT-Lizenz.