forked from jappel/leistungsbilanz-ts
Document authenticated deployment
This commit is contained in:
parent
847f4e9493
commit
3670f02ccd
9 changed files with 97 additions and 20 deletions
|
|
@ -7,10 +7,9 @@ Zugang wird von einem Administrator über **Config → Benutzer** angelegt.
|
|||
|
||||
Es gibt genau zwei Rollen (`src/shared/constants/user-roles.ts`):
|
||||
|
||||
- **admin** – wie `user`, zusätzlich Zugriff auf den Config-Bereich
|
||||
(Benutzerverwaltung, eigenes Konto)
|
||||
- **admin** – wie `user`, zusätzlich Zugriff auf **Config → Benutzer**
|
||||
- **user** – volle Nutzung der Leistungsbilanz (Projekte, Stromkreislisten,
|
||||
Grobbilanz, …), kein Zugriff auf Config
|
||||
Grobbilanz, …) und Zugriff auf das eigene Konto, keine Benutzerverwaltung
|
||||
|
||||
Es gibt (bewusst, siehe unten) keine konfigurierbare Rechte-Matrix und keine
|
||||
Verknüpfung mit einer Mitarbeiter-/Personen-Stammdatentabelle.
|
||||
|
|
@ -44,6 +43,8 @@ Verknüpfung mit einer Mitarbeiter-/Personen-Stammdatentabelle.
|
|||
- **Frontend:** `AuthProvider` lädt `/api/auth/me`; `LoginGate`
|
||||
(`src/app/layout.tsx`) zeigt Login- bzw. Passwortformular, solange nicht
|
||||
angemeldet bzw. `mustChangePassword` gesetzt ist, sonst die App.
|
||||
**Konto** ist für jede angemeldete Person erreichbar; **Benutzer** nur für
|
||||
Administratoren.
|
||||
|
||||
## Schutzmechanismen
|
||||
|
||||
|
|
@ -52,12 +53,12 @@ Verknüpfung mit einer Mitarbeiter-/Personen-Stammdatentabelle.
|
|||
| 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 |
|
||||
| CSRF über reines HTTP | Browser senden `Sec-Fetch-Site` nur an HTTPS-Adressen. Beim Zugriff per `http://…` im LAN greift deshalb nur SameSite=Lax (schützt gegen fremde Domains, nicht gegen andere Ports desselben Hosts). |
|
||||
| CSRF | SameSite=Lax **plus** `requireSameOriginForWrites`: jeder Schreibzugriff braucht `X-Leistungsbilanz-Request: 1`; fremde HTML-Formulare können den Header nicht setzen und ein fremder Fetch scheitert an der notwendigen CORS-Preflight-Anfrage. Ein vorhandener `Sec-Fetch-Site`-Header wird zusätzlich geprüft. |
|
||||
| CSRF über reines HTTP | Der eigene Anwendungsheader gilt auch dann, wenn Browser im HTTP-LAN keinen `Sec-Fetch-Site`-Header senden. Skripte und manuelle API-Aufrufe müssen ihn bei `POST`, `PUT`, `PATCH` und `DELETE` ausdrücklich mitsenden. |
|
||||
| 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 |
|
||||
| Aussperren | Der letzte aktive Admin kann weder herabgestuft noch deaktiviert werden; Prüfung und Änderung laufen atomar in einer SQLite-Transaktion. Der eigene 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 |
|
||||
|
|
@ -77,6 +78,18 @@ ignoriert; jeder weitere Zugang entsteht über Config → Benutzer. Die Werte
|
|||
gehören in eine lokale, nicht versionierte `.env` auf dem Deploy-Host, nicht
|
||||
in `compose.yaml` selbst.
|
||||
|
||||
```dotenv
|
||||
AUTH_BOOTSTRAP_USERNAME=admin
|
||||
AUTH_BOOTSTRAP_PASSWORT=<eigenes Startpasswort mit mindestens 12 Zeichen>
|
||||
AUTH_SESSION_HOURS=12
|
||||
AUTH_SESSION_MAX_DAYS=7
|
||||
COOKIE_SECURE=false
|
||||
```
|
||||
|
||||
Bei Zugriff über HTTPS muss `COOKIE_SECURE=true` gesetzt werden. Bei direktem
|
||||
HTTP-Zugriff im LAN bleibt es `false`, da der Browser das Session-Cookie sonst
|
||||
nicht speichert.
|
||||
|
||||
## Bewusst nicht umgesetzt (Stand jetzt)
|
||||
|
||||
- Konfigurierbare Rechte-Matrix statt fixer `admin`/`user`-Rollen
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue