Skip to content

Route-Login: E-Mail-Code verrät nicht mehr, ob eine Adresse freigeschaltet ist - #459

Merged
CallMeTechie merged 2 commits into
masterfrom
fix/route-auth-no-enumeration
Nov 9, 2026
Merged

CallMeTechie merged 2 commits into
masterfrom
fix/route-auth-no-enumeration

Conversation

@CallMeTechie

Copy link
Copy Markdown
Owner

Worum geht es

Beim Route-Login mit E-Mail-Code hat /route-auth/send-code bei einer falschen Adresse mit einem eigenen Fehler (email_mismatch) geantwortet. So ließ sich ausprobieren, welche Adresse für eine Route freigeschaltet ist.

Änderungen

Keine Rückschlüsse mehr auf die Adresse

  • send-code antwortet für jede Adresse gleich: Status 200, gleicher Text, mindestens 300 ms. Der Text lautet: „Falls diese Adresse für diese Seite freigeschaltet ist, haben wir Ihnen einen Code geschickt. Er ist 5 Minuten gültig.“ (en: „If this address has access to this page, we have sent you a code. It is valid for 5 minutes.“)
  • Die Mail geht im Hintergrund raus. Wie lange der Mailserver braucht oder ob der Versand scheitert, sieht man an der Antwort nicht. Ein gescheiterter Versand steht als route_auth_otp_failed im Protokoll.
  • Nur die Adresse der Route bekommt einen Code. Groß-/Kleinschreibung und Leerzeichen spielen keine Rolle, die Mail geht an die gespeicherte Adresse.
  • Code-Schritt: Ein falscher Code und „an diese Adresse wurde nie ein Code geschickt“ scheitern gleich: „Der Code stimmt nicht oder ist abgelaufen. Prüfen Sie ihn oder fordern Sie einen neuen Code an.“ Beide zählen auf dieselbe Kontosperre.
  • Prüfungen, die nicht von der Adresse abhängen, kommen zuerst und gelten für alle gleich: keine gültige Adresse ergibt 400 („Bitte geben Sie eine gültige E-Mail-Adresse ein.“), kein SMTP eingerichtet ergibt 503 („Der Code kann gerade nicht verschickt werden. Bitte wenden Sie sich an die Person, die diese Seite betreibt.“).

IP-Sperre und Protokoll

  • Wird ein Code für eine fremde Adresse angefordert, zählt das für die IP-Sperre mit dem Gewicht „Unbekannte Benutzernamen“ (unknown_user_weight, Standard 3). Es läuft über denselben Weg wie beim Admin-Login (lockout.recordFailedAttempt(…, 'route_auth', ip, { unknownUser: true })).
  • Ein falscher Code zählt wie bisher einfach.
  • Neues Activity-Ereignis route_auth_failed (warning) für Fehlversuche am Route-Login. Es enthält die Route, die gekürzte Adresse (s***@example.com), die IP und den Schritt (password, code_request oder code). Bei fremden Adressen kommt unknownUser: true dazu. Passwort und Code werden nie protokolliert.

Nebenbei behoben (gleicher Ablauf)

  • „Code erneut senden“ beim zweiten Faktor hat die leere Eingabe mit der Adresse verglichen und ist deshalb immer gescheitert. Jetzt geht der Code an die Adresse der wartenden Sitzung.
  • Beim reinen E-Mail-Code-Login hat send-code bisher eine wartende 2FA-Sitzung verlangt. Ohne Sitzung kam „Sitzung abgelaufen“, deshalb konnte man gar keinen Code anfordern.
  • Eine wartende 2FA-Sitzung gilt nur noch für ihre eigene Route. Das betrifft die Login-Seite (Schritt 2, gekürzte Adresse), send-code und verify-code. Die gekürzte Adresse kommt aus der Sitzung und nicht mehr aus der Routen-Konfiguration.
  • Auch beim zweiten Faktor wartet der Mailversand nicht mehr auf den Mailserver.

Die bestehenden Limits bleiben unverändert: send-code 3 pro 5 min und IP, verify-code 5 pro 15 min und IP, Kontosperre, Code 5 Minuten gültig.

Doku: FEATURES.md (Route Auth, Tabelle zur Gewichtung), Handbuch-FAQ und Guide-FAQ.

Tests

  • Neu: tests/route_auth_no_enumeration.test.js mit 10 Tests. Geprüft werden gleiche Antwort und Mindestzeit, Gewicht 3 bzw. 5, Protokolleintrag, Groß-/Kleinschreibung, Mailverzögerung und Mailfehler, 400/503, der Code-Schritt (falsch und nie gesendet, richtiger Code) sowie das erneute Senden beim zweiten Faktor und die Bindung der Sitzung an ihre Route.
  • npm test lokal mit Node 22: 5958 bestanden. Es scheitern nur die zwei bekannten lokalen Tests (config_hash_stub_guard, plugins_lifecycle „acting user“).

Generated by Claude Code

…altet ist

- /route-auth/send-code antwortet für jede Adresse gleich (Status, Text,
  mindestens 300 ms); die Mail geht im Hintergrund raus, Verzögerung oder
  Fehler beim Versand erreichen die Antwort nicht (route_auth_otp_failed).
- Nur die Adresse der Route bekommt einen Code (Groß-/Kleinschreibung und
  Leerzeichen egal). Eine andere Adresse zählt für die IP-Sperre mit dem
  Gewicht "Unbekannte Benutzernamen" (unknown_user_weight).
- Code-Schritt: falscher Code und "nie ein Code geschickt" scheitern gleich;
  ein falscher Code zählt einfach.
- "Code erneut senden" beim zweiten Faktor geht an die Adresse der
  wartenden Sitzung (bisher wurde die leere Eingabe verglichen); die
  wartende Sitzung gilt nur für ihre eigene Route.
- Fehlversuche stehen als route_auth_failed im Protokoll (Route, gekürzte
  Adresse, IP, Schritt).
- Doku: FEATURES, Handbuch- und Guide-FAQ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xX1efcZF1f6G9rhmaJNLD
@CallMeTechie
CallMeTechie merged commit ff953ae into master Nov 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants