Mass-Assignment-Schutz: Nested-Vertragsdetails (Pentest R162-01)

createContract/updateContract spreadeten energyDetails/tvDetails/
carInsuranceDetails/mobileDetails (via ...mobileData) roh an Prisma.
Injizierte id/contractId konnten ein Detail-Objekt auf einen Fremdvertrag
reparenten oder den PK frei setzen (stilles 200 statt 400) - MEDIUM
(Integritaet; kein Cross-Tenant, staff-only, Portal 403).

Fix: Feld-Whitelists (pickEnergyScalars/pickMobileScalars/pickTvScalars/
pickCarInsuranceScalars, analog R158) an allen Spread-Stellen in create+update.
internet war bereits explizit (preparedInternetData) - safe. Whitelists
programmatisch gegen die DB-Spalten abgeglichen (minus id/contractId/
verschluesselt) - alle Diffs leer.

Verifiziert: energyDetails{basePrice:99.99, id:999999, contractId:fremd}
-> basePrice aktualisiert, ecd.id + contractId unveraendert (kein Reparenting).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 16:10:45 +02:00
co-authored by Claude Opus 4.8
parent 8964820542
commit 7bdb885a10
2 changed files with 60 additions and 15 deletions
+13
View File
@@ -97,6 +97,19 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
- [x] **🔒 Mass-Assignment-Schutz: Nested-Vertragsdetails (Pentest R162-01)** (2026-08-18)
- `createContract`/`updateContract` spreadeten `energyDetails`/`tvDetails`/
`carInsuranceDetails`/`mobileDetails` (via `...mobileData`) roh an Prisma →
injizierte `id`/`contractId` konnten ein Detail-Objekt **reparenten** (auf
Fremdvertrag umhängen) oder den **PK frei setzen** (stilles 200 statt 400).
MEDIUM (Integrität; kein Cross-Tenant, staff-only, Portal 403).
- **Fix:** Feld-Whitelists (`pickEnergyScalars`/`pickMobileScalars`/`pickTvScalars`/
`pickCarInsuranceScalars`, analog R158) an allen Spread-Stellen. `internet`
war bereits explizit (safe). Whitelists programmatisch gegen die DB-Spalten
abgeglichen (minus id/contractId/verschlüsselt) alle Diffs leer.
- Verifiziert: `energyDetails:{basePrice:99.99, id:999999, contractId:fremd}`
basePrice aktualisiert, ecd.id + contractId **unverändert** (kein Reparenting).
- [x] **📋 Aufgaben ohne Kunde/Vertrag anlegbar** (2026-08-18)
- `ContractTask.contractId` nullable (Migration `20260818110000`). Neuer Endpoint
`POST /tasks` (staff-only, `contracts:update`) für allgemeine Aufgaben ohne