Commit Graph
2 Commits
Author SHA1 Message Date
Nick SzaunigandClaude Opus 5.5 45ca0ea745 test(session): tamper inside the signature, not its last character
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m28s
The last base64url character of a 32-byte HMAC signature partly carries
padding bits that decoders ignore, so the tampered token was sometimes
still valid and the test failed at random. Changing a character in the
middle of the signature always alters the signature bytes.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 05:39:09 +02:00
Nick SzaunigandClaude Opus 5 3e81896194 fix: Session-Pruefung akzeptierte Token anderer Zwecke
Alle Token in lib/session.ts sind mit DEMSELBEN Geheimnis signiert und
tragen denselben Aussteller und dieselbe Zielgruppe. Unterschieden werden
sie allein ueber ein "type"-Feld — und genau das prueft
verifySessionToken nicht. Es verlangte nur eine vorhandene "sub".

Damit bestand ein 2FA-Challenge-Token die Session-Pruefung und galt als
vollwertige Anmeldung. Dieses Cookie wird ausgestellt, NACHDEM das
Passwort stimmt, aber BEVOR der zweite Faktor geprueft ist: wer es im
Browser in das Session-Cookie kopiert, umgeht die Zwei-Faktor-Pruefung.
Praktisch nachgestellt:

  signTwoFactorChallenge("customer_123")
  -> verifySessionToken(...) ergab
     { customerId: "customer_123", role: "KUNDE", sessionVersion: 0 }

Dasselbe galt fuer den 2FA-Einrichtungstoken und den Token der
Backup-Code-Anzeige. Der Entra-OAuth-State trug keine "sub" und fiel
schon vorher durch.

Aufgehalten wurde das bisher nur zufaellig: diese Token fuehren keine
sessionVersion (also 0), und getCurrentCustomer vergleicht sie gegen die
Datenbank — wer 2FA aktiviert, steht dort bereits bei mindestens 1
(konto/actions/two-factor.ts zaehlt hoch). Das ist eine Sperre, die aus
einem voellig anderen Grund existiert und lautlos wegfaellt, sobald sich
an Zaehler oder Token etwas aendert.

verifySessionToken lehnt jetzt jeden Token mit "type"-Feld ab. Geprueft
wird auf ABWESENHEIT, nicht auf einen bestimmten Wert: das Session-Token
setzt selbst kein "type", bestehende Cookies bleiben also gueltig und
niemand wird durch das Ausrollen abgemeldet.

Dazu die erste Testabdeckung fuer die Token-Schicht ueberhaupt
(lib/session.test.ts, 12 Faelle): Rundlauf, manipulierter Token,
unbekannte Rolle wird auf KUNDE heruntergestuft, und jede Kombination von
Token-Verwechslung in beide Richtungen. Die Datei laeuft bewusst in der
node-Umgebung — jose prueft mit "instanceof Uint8Array", und jsdoms
TextEncoder liefert ein Uint8Array aus einem anderen Realm.

Nebenbei in honig/actions.ts: toggleWishlistAction nahm die productId
ungeprueft aus dem Formular. Ein erfundener Wert lief in eine
Fremdschluesselverletzung und damit in die allgemeine Fehlerseite — ein
500er als Antwort auf eine schlicht ungueltige Eingabe. Jetzt wird die
Existenz geprueft, und ein deaktiviertes Produkt kommt nicht neu auf eine
Wunschliste.

tsc: 0 Fehler. vitest: 328/328 gruen (zuvor 316). eslint: 0 Warnungen.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-19 02:30:47 +02:00