Security-Hardening Runde 15: Pentest Runde 12 Folge-Fixes
M2-Reste – XSS-Strings + Mass-Assignment-Settings noch in DB:
Idempotentes Cleanup-Script prisma/cleanup-xss-and-mass-assignment.ts.
Strippt HTML aus Customer/User-String-Feldern, entfernt AppSettings
ohne Whitelist-Eintrag. Wird im entrypoint.sh nach Migrations + Seed
einmalig pro Container-Start ausgeführt.
User-Update + password-Feld:
password aus USER_UPDATABLE_FIELDS raus (CREATE behält es), neuer
dedizierter Endpoint POST /api/users/:id/password mit Audit-Log
"Passwort … durch Admin gesetzt" und Komplexitäts-Check.
JS-Runtime-Fehler-Leak:
ORM_LEAK_PATTERNS um TypeError/ReferenceError/SyntaxError/RangeError +
"Cannot read properties of undefined/null" + "is not a function/
defined" erweitert. Greift im globalen res.json()-Wrapper.
POST /contracts substring-Crash:
Controller validiert type/customerId, sonst 400. generateContractNumber
fängt nullish type ab (Fallback "CON").
Seed-Admin-Passwort:
Default "admin" verletzte 12-Zeichen-Policy. Jetzt 16-char
Zufallspasswort (alle 4 Klassen garantiert via Fisher-Yates) oder per
SEED_ADMIN_PASSWORD-ENV überschreibbar. BCRYPT-Cost 12 (war 10).
Passwort wird einmalig in stdout ausgegeben mit Warnung.
AppSettings-Whitelist: companyName + defaultEmailDomain ergänzt
(kamen aus seed.ts, in 1. Whitelist vergessen).
Live-verifiziert:
- POST /contracts {} → 400 "Vertrags-Typ erforderlich" (vorher
TypeError-Stack)
- PUT /users/6 {password:"HackerPW2026!"} → 200 aber Login mit altem
PW geht weiter
- POST /users/6/password mit "kurz" → 400 mit Komplexitäts-Fehlern
- Cleanup-Script: planted XSS bereinigt, hackerSetting+debugMode
entfernt, idempotenter Re-Lauf
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,39 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🚨 Pentest Runde 12 – Folge-Fixes: XSS-Reste, User-PW-Endpoint, JS-Error-Leak, Seed-PW**
|
||||
- **M2-Reste (XSS-Strings noch in DB)**: neues idempotentes Script
|
||||
`prisma/cleanup-xss-and-mass-assignment.ts` läuft beim
|
||||
Container-Start. Strippt HTML aus Customer/User-String-Feldern;
|
||||
entfernt AppSettings, deren Key nicht in `ALLOWED_SETTING_KEYS`
|
||||
steht. Mehrfacher Aufruf ändert nichts.
|
||||
- **User-Update akzeptierte `password`-Feld**: stillschweigend ohne
|
||||
dedizierten Audit-Eintrag. Jetzt: `password` aus
|
||||
`USER_UPDATABLE_FIELDS` raus (CREATE behält es weiterhin); neuer
|
||||
Endpoint `POST /api/users/:id/password` mit eigenem Audit-Log
|
||||
"Passwort … durch Admin gesetzt", Komplexitäts-Check inklusive.
|
||||
- **JS-Runtime-Fehler leakten weiter**: ORM-Leak-Patterns erweitert
|
||||
um `TypeError`, `ReferenceError`, `SyntaxError`, `RangeError`,
|
||||
"Cannot read propert(y|ies) of (undefined|null)", "is not a
|
||||
function", "is not defined". Greift im globalen
|
||||
`res.json()`-Wrapper.
|
||||
- **POST /contracts substring-Crash**: defensiv – `type` fehlt →
|
||||
400 mit klarer Meldung; `generateContractNumber()` fängt auch
|
||||
leere/null type ab (Fallback "CON").
|
||||
- **Seed-Admin-Passwort "admin" verletzte Policy**: jetzt
|
||||
16-Zeichen-Zufallspasswort beim Seed (mit allen 4 Klassen
|
||||
garantiert) oder via `SEED_ADMIN_PASSWORD`-ENV überschreibbar;
|
||||
BCRYPT-Cost auf 12 (war 10); Passwort wird **einmalig** beim
|
||||
Seed in stdout ausgegeben mit Warnung.
|
||||
- **AppSettings-Whitelist ergänzt**: `companyName`,
|
||||
`defaultEmailDomain` (kommen aus seed.ts, waren in der ersten
|
||||
Whitelist vergessen).
|
||||
- **Live-verifiziert**: POST /contracts {} → klare 400 statt
|
||||
JS-Crash; PUT /users/6 {password:...} ignoriert (Login mit
|
||||
altem PW geht weiter); POST /users/6/password mit kurz → 400;
|
||||
Cleanup-Script: 1 Customer bereinigt, 2 unbekannte AppSettings
|
||||
entfernt (hackerSetting, debugMode), Re-Lauf → 0 Änderungen.
|
||||
|
||||
- [x] **🚨 Pentest Runde 11 – Factory-Reset, Settings-Whitelist, Prisma-Leak, XSS-Strip**
|
||||
- **C2 KRITISCH – Factory Reset ohne Bestätigung**:
|
||||
Eingeloggter Admin konnte mit leerem oder beliebigem Body
|
||||
|
||||
Reference in New Issue
Block a user