Security-Hardening Runde 14: Factory-Reset, Settings-Whitelist, Prisma-Leak, XSS-Strip

Pentest Runde 11:

C2 KRITISCH – Factory Reset ohne Bestätigung:
Eingeloggter Admin konnte mit leerem oder beliebigem Body die DB
plätten (3× in einer Pentest-Session passiert). Server erzwingt jetzt
confirm:"FACTORY-RESET-BESTAETIGT" als String. Frontend-API sendet
den Wert automatisch mit.

M1 – Settings Mass Assignment:
PUT /api/settings akzeptierte beliebige Keys (superAdminEmail,
debugMode, allowedOrigins). Neue Whitelist ALLOWED_SETTING_KEYS in
appSetting.service.ts; updateSetting + updateSettings prüfen jeden
Key, unbekannte → 400.

M3 – Prisma-Error-Leak:
Statt 30+ Controller einzeln zu fixen, globaler res.json()-Wrapper
unter /api: error/details-Strings werden durch Pattern-Filter
geschickt, der ORM-/Stack-Trace-Muster zu "Operation fehlgeschlagen"
ersetzt. Original bleibt im Server-Log.

M2 – Stored XSS in Customer/User-Strings:
Neuer stripHtml()-Helper. pickCustomerUpdate/Create + pickUserUpdate/
Create rufen ihn auf jeden String-Wert. Defense-in-Depth gegen PDF/
E-Mail-Template-XSS-Vektoren – React-Frontend ist eh auto-escaped.

Live-verifiziert:
- factory-reset {} / {confirm:true} / {confirm:false} → 400, DB ok
- PUT /settings {superAdminEmail,...} → 400 + Keys aufgezählt;
  PUT /settings {customerSupportTicketsEnabled:"true"} → 200
- PUT /users/99999 → "Operation fehlgeschlagen" (vorher Prisma-Stack)
- PUT /customers/3 {companyName:"<script>...</script>EvilCorp"} →
  gespeichert als "EvilCorp"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 05:23:12 +02:00
parent ef238b0145
commit d545790a69
7 changed files with 168 additions and 8 deletions
+38
View File
@@ -97,6 +97,44 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
- [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
(`{confirm:true}`, `{confirm:false}`, `{}`) die komplette DB
plätten (3× in einer Session passiert). Fix: server-side wird
jetzt `confirm: "FACTORY-RESET-BESTAETIGT"` als String erzwungen,
sonst HTTP 400. Frontend-API schickt den exakten String mit.
- **M1 Settings Mass Assignment**:
`PUT /api/settings` und `PUT /api/settings/:key` nahmen JEDEN
Key-Value-Pair an (`superAdminEmail`, `debugMode`,
`allowedOrigins` etc. landeten direkt in der DB). Fix:
Whitelist `ALLOWED_SETTING_KEYS` in `appSetting.service.ts`,
Helper `isAllowedSettingKey()`. Unbekannte Keys → HTTP 400 mit
expliziter Aufzählung der ungültigen Keys.
- **M3 Prisma-Error-Leak in jeder Response**:
Statt 30+ Controller einzeln zu fixen: globaler `res.json()`-
Wrapper unter `/api`, der `error`/`details`-Strings durch einen
Pattern-Filter schickt. Bekannte ORM-/Stack-Trace-Muster
(`Invalid \`prisma.`, `PrismaClient`, Stack-Frames) werden zu
`"Operation fehlgeschlagen"` ersetzt. Original-Text bleibt im
Server-Log via `[orm-leak-guard]`.
- **M2 Stored XSS in Customer/User-Strings**:
`<script>alert(1)</script>` und ähnliche Payloads landeten
ungefiltert in der DB. Fix: neuer `stripHtml()`-Helper, von
`pickCustomerUpdate/Create` und `pickUserUpdate/Create` auf
allen String-Werten angewandt (Defense-in-Depth React
auto-escaped schon, aber PDF-Generator/E-Mail-Templates
könnten exec-Vektoren sein).
- **Live-verifiziert (alle vier)**:
* `/factory-reset` mit `{}`, `{confirm:true}`, `{confirm:false}`
→ HTTP 400, DB unangetastet
* `PUT /settings {superAdminEmail,debugMode,allowedOrigins}` →
400 + Keys aufgezählt; gültige Keys → 200
* `PUT /users/99999` → `"Operation fehlgeschlagen"` statt
Prisma-Stack; Server-Log behält Original
* `PUT /customers/3 {companyName:"<script>...</script>EvilCorp"}`
→ gespeichert als `"EvilCorp"`; `<img onerror>` weg
- [x] **🚨 Pentest Runde 10 Live-Vollmacht-Konsistenz + DTO-Leaks in embedded Objekten**
- **MEDIUM Stale Token nach Vollmacht-Widerruf**:
Selbst ein FRISCHER Portal-Login lieferte JWT mit