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 <noreply@anthropic.com>
This commit is contained in:
@@ -238,10 +238,17 @@ export async function createAddress(
|
||||
});
|
||||
}
|
||||
|
||||
// Explizite Feld-Whitelist (Mass-Assignment-Schutz, Pentest R155).
|
||||
return prisma.address.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
type: data.type,
|
||||
street: data.street,
|
||||
houseNumber: data.houseNumber,
|
||||
postalCode: data.postalCode,
|
||||
city: data.city,
|
||||
country: data.country,
|
||||
isDefault: data.isDefault,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -272,9 +279,18 @@ export async function updateAddress(
|
||||
});
|
||||
}
|
||||
|
||||
// Explizite Feld-Whitelist (Mass-Assignment-Schutz, Pentest R155).
|
||||
return prisma.address.update({
|
||||
where: { id },
|
||||
data,
|
||||
data: {
|
||||
type: data.type,
|
||||
street: data.street,
|
||||
houseNumber: data.houseNumber,
|
||||
postalCode: data.postalCode,
|
||||
city: data.city,
|
||||
country: data.country,
|
||||
isDefault: data.isDefault,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -309,10 +325,18 @@ export async function createBankCard(
|
||||
description?: string;
|
||||
}
|
||||
) {
|
||||
// Explizite Feld-Whitelist statt `...data`-Spread: verhindert Mass-Assignment
|
||||
// (Pentest R155). Sonst könnte roher req.body u.a. `customerId`/`id` setzen.
|
||||
return prisma.bankCard.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
accountHolder: data.accountHolder,
|
||||
iban: data.iban,
|
||||
cardNumber: data.cardNumber,
|
||||
bic: data.bic,
|
||||
bankName: data.bankName,
|
||||
expiryDate: data.expiryDate,
|
||||
description: data.description,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
@@ -331,9 +355,21 @@ export async function updateBankCard(
|
||||
isActive?: boolean;
|
||||
}
|
||||
) {
|
||||
// Explizite Feld-Whitelist statt `data`-Passthrough: verhindert Mass-
|
||||
// Assignment (Pentest R155 – roher req.body konnte `customerId`/`id`
|
||||
// mutieren). Undefined-Felder ignoriert Prisma → Partial-Update bleibt.
|
||||
return prisma.bankCard.update({
|
||||
where: { id },
|
||||
data,
|
||||
data: {
|
||||
accountHolder: data.accountHolder,
|
||||
iban: data.iban,
|
||||
cardNumber: data.cardNumber,
|
||||
bic: data.bic,
|
||||
bankName: data.bankName,
|
||||
expiryDate: data.expiryDate,
|
||||
description: data.description,
|
||||
isActive: data.isActive,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -373,10 +409,17 @@ export async function createDocument(
|
||||
licenseIssueDate?: Date;
|
||||
}
|
||||
) {
|
||||
// Explizite Feld-Whitelist (Mass-Assignment-Schutz, Pentest R155).
|
||||
return prisma.identityDocument.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
type: data.type,
|
||||
documentNumber: data.documentNumber,
|
||||
issuingAuthority: data.issuingAuthority,
|
||||
issueDate: data.issueDate,
|
||||
expiryDate: data.expiryDate,
|
||||
licenseClasses: data.licenseClasses,
|
||||
licenseIssueDate: data.licenseIssueDate,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
@@ -395,9 +438,19 @@ export async function updateDocument(
|
||||
isActive?: boolean;
|
||||
}
|
||||
) {
|
||||
// Explizite Feld-Whitelist (Mass-Assignment-Schutz, Pentest R155).
|
||||
return prisma.identityDocument.update({
|
||||
where: { id },
|
||||
data,
|
||||
data: {
|
||||
type: data.type,
|
||||
documentNumber: data.documentNumber,
|
||||
issuingAuthority: data.issuingAuthority,
|
||||
issueDate: data.issueDate,
|
||||
expiryDate: data.expiryDate,
|
||||
licenseClasses: data.licenseClasses,
|
||||
licenseIssueDate: data.licenseIssueDate,
|
||||
isActive: data.isActive,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user