Harden authentication and put filter toggle and fields in one row
Security: per-username login throttling, constant-time unknown-user check, Sec-Fetch-Site CSRF guard for writes, session rotation on login and password change, absolute session lifetime, sessions ended on reset and deactivation, last-admin protection, input length caps, ASCII usernames, clickjacking headers. Covered by tests/authentication.test.ts. Filter panel: toggle, fields and count share one row to save space. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8d2948cdb1
commit
5073d9342a
18 changed files with 683 additions and 81 deletions
|
|
@ -33,7 +33,8 @@ Verknüpfung mit einer Mitarbeiter-/Personen-Stammdatentabelle.
|
|||
`username`, `passwordHash` (scrypt, `src/server/auth/password.ts`), `name`,
|
||||
`role`, `active`, `mustChangePassword`.
|
||||
- **Sessions:** In-Memory-Store (`src/server/auth/sessions.ts`), Cookie
|
||||
`lb_session`, sliding expiry (`AUTH_SESSION_HOURS`, Standard 12h). Ein
|
||||
`lb_session`, sliding expiry (`AUTH_SESSION_HOURS`, Standard 12h) mit
|
||||
absoluter Obergrenze (`AUTH_SESSION_MAX_DAYS`, Standard 7). Ein
|
||||
Neustart der API beendet alle Sessions – für einen Single-Container-Dienst
|
||||
ein akzeptabler Kompromiss gegenüber einer persistierten Session-Tabelle.
|
||||
- **Middleware:** `src/server/auth/auth.middleware.ts` schützt `/api/*`
|
||||
|
|
@ -44,6 +45,28 @@ Verknüpfung mit einer Mitarbeiter-/Personen-Stammdatentabelle.
|
|||
(`src/app/layout.tsx`) zeigt Login- bzw. Passwortformular, solange nicht
|
||||
angemeldet bzw. `mustChangePassword` gesetzt ist, sonst die App.
|
||||
|
||||
## Schutzmechanismen
|
||||
|
||||
| Angriff | Schutz |
|
||||
|---|---|
|
||||
| Passwort-Raten (online) | `LoginThrottle`: 5 Fehlversuche je Anmeldename in 15 min → HTTP 429 bis das Fenster abläuft. Schlüssel ist der Name, nicht die IP (alle Anfragen kommen über den Next-Rewrite mit derselben Quell-IP). |
|
||||
| Passwort-Raten (offline, DB-Diebstahl) | scrypt (N=16384, r=8, p=1), eigenes Salt je Hash |
|
||||
| Nutzernamen ausspähen (Timing) | Unbekannte Namen werden gegen einen festen Dummy-Hash geprüft – immer genau ein scrypt-Lauf; einheitliche Fehlermeldung |
|
||||
| CSRF | SameSite=Lax **plus** `requireSameOriginForWrites`: schreibende Anfragen nur mit `Sec-Fetch-Site: same-origin`. Nötig, weil andere Dienste auf demselben Host (andere Ports) als „same-site“ gelten |
|
||||
| Session-Fixation | Neue Session-ID bei jedem Login und nach jedem Passwortwechsel |
|
||||
| Gestohlenes Cookie | httpOnly; gleitende Laufzeit (`AUTH_SESSION_HOURS`, 12 h) **und** harte Obergrenze (`AUTH_SESSION_MAX_DAYS`, 7 Tage) |
|
||||
| Kompromittiertes Konto | Passwort-Reset und Deaktivieren beenden sofort alle Sessions des Kontos; Passwortwechsel beendet alle anderen |
|
||||
| Aussperren | Der letzte aktive Admin kann weder herabgestuft noch deaktiviert werden; eigener Zugang ist in der Liste gesperrt |
|
||||
| Rechteausweitung / Mass Assignment | Rolle kommt aus der DB, nie aus der Anfrage; zod-Schemas mit `.strict()` |
|
||||
| DoS über riesige Passwörter | Längengrenzen (Name 100, Passwort 200 Zeichen) vor scrypt |
|
||||
| Look-alike-Namen | Anmeldename nur `a-z 0-9 . _ @ -`, klein geschrieben |
|
||||
| Clickjacking | `X-Frame-Options: SAMEORIGIN`, `frame-ancestors 'self'` (next.config.mjs) |
|
||||
| Speicherwachstum | Max. 20 Sessions je Nutzer, periodisches Aufräumen abgelaufener Sessions, Throttle-Tabelle begrenzt |
|
||||
|
||||
**Nicht durch Code lösbar:** Ohne TLS gehen Passwort und Session-Cookie im
|
||||
Klartext durchs Netz. Für Zugriff außerhalb des LANs HTTPS über einen
|
||||
Reverse-Proxy vorschalten und `COOKIE_SECURE=true` setzen.
|
||||
|
||||
## Bootstrap-Admin
|
||||
|
||||
`AUTH_BOOTSTRAP_USERNAME` / `AUTH_BOOTSTRAP_PASSWORT` (Env-Variablen, siehe
|
||||
|
|
@ -56,6 +79,7 @@ in `compose.yaml` selbst.
|
|||
## Bewusst nicht umgesetzt (Stand jetzt)
|
||||
|
||||
- Konfigurierbare Rechte-Matrix statt fixer `admin`/`user`-Rollen
|
||||
- Konten-Sperre nach Fehlversuchen
|
||||
- Dauerhafte Konten-Sperre nach Fehlversuchen (es gibt nur die zeitlich
|
||||
begrenzte Drosselung, siehe oben)
|
||||
- E-Mail-/Einmal-Link-Passwortvergabe, OIDC/Entra-Anmeldung
|
||||
- Verknüpfung von Zugängen mit einer Mitarbeiter-Stammdatentabelle
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue