todo.md: Passwort-Komplexität + Real-IP-Fix dokumentiert

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 18:26:52 +02:00
parent 8a5ffbb563
commit f0c97cd46d
+40
View File
@@ -97,6 +97,46 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
- [x] **🔐 Passwort-Komplexität + Portal-Credentials-UX**
- **Problem**: Bisher reichten 6 Zeichen für gesetzte Passwörter
(Portal-Login, User-Reset, Registrierung, User-Anlage). Das hat
der Pentest bemängelt, und es entsprach auch nicht dem, was wir
selbst von Endkunden erwarten würden.
- **Lösung**:
* `validatePasswordComplexity()` in `passwordGenerator.ts`:
mind. 12 Zeichen + Großbuchstaben + Kleinbuchstaben + Ziffer
+ Sonderzeichen, mit detaillierter Fehlerliste auf deutsch.
* Erzwungen in **5 Endpoints**: `setPortalPassword`,
`confirmPasswordReset`, `register`, `createUser`, `updateUser`.
- **Neue UX im Kunden-Portal-Block (CustomerDetail)**:
* **Generate-Button**: erzeugt 16-Zeichen-Zufallspasswort, das
garantiert allen Komplexitätsregeln entspricht, und füllt
das Eingabefeld direkt aus.
* **Send-Credentials-Button**: schickt Login-URL + Username +
Klartext-Passwort an die Kunden-E-Mail. Funktioniert nur,
wenn "Portal aktiviert" tatsächlich aktiviert ist.
* **Live-Komplexitäts-Hint** beim Tippen: ✓/○-Liste zeigt
sofort, welche Regeln noch fehlen.
* `alert()`-Boxen durch Toast-Notifications ersetzt.
- **Live-verifiziert**: schwaches Passwort `hallo123` → HTTP 400
mit Fehlerliste, komplexes Passwort `Hallo123!Test` → HTTP 200,
Generator-Endpoint liefert 16-Zeichen-Passwort, Send-Credentials
versendet Mail nur bei portalEnabled=true.
- [x] **🌐 Real-IP hinter Nginx-Proxy-Manager**
- **Problem**: Rate-Limiter und Security-Monitor haben statt der
echten Client-IP nur die NPM-IP (`172.0.2.12`) geloggt. Damit
wären alle Threshold-basierten Blockings nutzlos ein Brute-
Force von 100 verschiedenen Clients wäre für uns 1 Quelle.
- **Root Cause**: `app.set('trust proxy', 'loopback')` das passt
nur, wenn der Proxy auf 127.0.0.1 läuft. NPM läuft aber auf
einem anderen Host, also wurde X-Forwarded-For ignoriert.
- **Fix**: trust-proxy abhängig von `HTTPS_ENABLED`:
`HTTPS_ENABLED=true``1` (genau 1 Hop, der NPM), sonst
`loopback` (Direkt-Verbindungen lokal).
- **Live-verifiziert**: req.ip zeigt jetzt die echte Browser-IP
statt der NPM-IP, Threshold-Events triggern korrekt.
- [x] **🚨 KRITISCH: IDOR auf Stressfrei-Email-Sub-Routes (Pentest-Fund)**
- **Realer Angriff erfolgreich durchgespielt**: Portal-User konnte über
`/api/stressfrei-emails/{id}/credentials` die kompletten Klartext-