From cb21a2c9be3320a582f1c74aab0abc7151de5d2c Mon Sep 17 00:00:00 2001 From: duffyduck Date: Thu, 13 Aug 2026 16:40:15 +0200 Subject: [PATCH] Mass-Assignment-Schutz: Bankkarte/Adresse/Ausweis (Pentest R155) Die create/update-Services reichten rohen req.body an Prisma durch, wodurch customerId (Owner) und id (PK) per Update mutierbar waren - staff-only, kein Cross-Tenant-Bruch, aber echte Integritaetsschwaeche; mit dem neuen cardNumber-Feld liegt zudem Finanz-PII auf dieser Flaeche. Fix: explizite Feld-Whitelist im Service (create+update) fuer BankCard, Address und IdentityDocument - nur benannte Spalten gehen an Prisma, kein ...data/req.body-Spread mehr. Controller-Helper pickBankCardFields haelt zusaetzlich die Audit-Logs sauber (keine Phantom-Eintraege injizierter Keys). Verifiziert: updateBankCard mit {customerId:99999, id:88888, bogusField, ...} -> id+customerId unveraendert, nur cardNumber gesetzt, Fremdfelder ignoriert. Co-Authored-By: Claude Opus 4.8 --- .../src/controllers/customer.controller.ts | 25 ++++++- backend/src/services/customer.service.ts | 65 +++++++++++++++++-- docs/todo.md | 11 ++++ 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/backend/src/controllers/customer.controller.ts b/backend/src/controllers/customer.controller.ts index 059cf6fb..34fe55b1 100644 --- a/backend/src/controllers/customer.controller.ts +++ b/backend/src/controllers/customer.controller.ts @@ -24,6 +24,23 @@ import { } from '../utils/accessControl.js'; import { ApiError } from '../utils/apiError.js'; +// Mass-Assignment-Schutz für Bankkarten (Pentest R155): nur diese Felder dürfen +// aus dem Request-Body übernommen werden – NICHT customerId/id/createdAt/… Nur +// tatsächlich gesendete Keys landen im Ergebnis, damit Partial-Updates und das +// Änderungs-Audit korrekt bleiben. +const BANK_CARD_ALLOWED_FIELDS = [ + 'accountHolder', 'iban', 'cardNumber', 'bic', 'bankName', 'expiryDate', 'description', 'isActive', +] as const; + +function pickBankCardFields(body: unknown): Record { + const src = (body && typeof body === 'object') ? (body as Record) : {}; + const out: Record = {}; + for (const key of BANK_CARD_ALLOWED_FIELDS) { + if (key in src) out[key] = src[key]; + } + return out; +} + // Customer CRUD export async function getCustomers(req: AuthRequest, res: Response): Promise { try { @@ -401,7 +418,8 @@ export async function createBankCard(req: AuthRequest, res: Response): Promise