Security-Hardening Runde 16: KRITISCH – Update-Responses sanitisieren
Pentest Runde 15: 20.3 KRITISCH: PUT /customers/:id gab portalPasswordHash (bcrypt $2a$12$…) im Response zurück. updateCustomer reichte das rohe Service-Output ohne sanitize-Aufruf durch. 20.4 HOCH (gleiche Klasse): PUT-Response leakte portalPasswordResetToken, portalPasswordMustChange, consentHash, portalTokenInvalidatedAt. Fix: - updateCustomer + createCustomer rufen sanitizeCustomer bzw. sanitizeCustomerStrict je nach customers:update-Permission. - updateContract + createContract + createFollowUp + createRenewal analog mit sanitizeContract / sanitizeContractStrict je nach isCustomerPortal. - portalPasswordMustChange + portalTokenInvalidatedAt von PORTAL_HIDDEN_CUSTOMER_FIELDS zu SENSITIVE_CUSTOMER_FIELDS hochgezogen → greift auch in normaler sanitizeCustomer (Admin-Sicht). Live-verifiziert: - Admin PUT /customers/3 → 0 Leaks von Hash/Token/Expires/MustChange/ consentHash/TokenInvalidatedAt; portalPasswordEncrypted bleibt für Admin sichtbar (UI-Workflow, separater Endpoint mit Audit) - POST /customers → 0 Leaks - Portal-User GET /customers/3 → 0 Leaks auch bei portalPasswordEncrypted/notes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,35 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🚨 Pentest Runde 15 – KRITISCH: portalPasswordHash in PUT/POST-Response**
|
||||
- **20.3 KRITISCH**: `PUT /customers/:id` gab den vollen bcrypt-Hash
|
||||
(`$2a$12$…`) zurück, weil `updateCustomer` Service-Output ohne
|
||||
sanitize-Aufruf direkt durchreichte. GET-Endpoints waren dicht,
|
||||
die Update-Response nicht. **20.4 HOCH** gleicher Klasse:
|
||||
`portalPasswordResetToken`, `consentHash`,
|
||||
`portalPasswordMustChange`, `portalTokenInvalidatedAt` leakten
|
||||
ebenfalls über PUT/POST.
|
||||
- **Fix**:
|
||||
* `updateCustomer` + `createCustomer` rufen jetzt
|
||||
`sanitizeCustomer`/`sanitizeCustomerStrict` auf den Service-
|
||||
Output (je nach `customers:update`-Permission).
|
||||
* `updateContract` + `createContract` + `createFollowUp` +
|
||||
`createRenewal` analog mit `sanitizeContract`/Strict
|
||||
(Portal-Hint via `req.user.isCustomerPortal`).
|
||||
* `portalPasswordMustChange` und `portalTokenInvalidatedAt`
|
||||
zusätzlich von `PORTAL_HIDDEN_CUSTOMER_FIELDS` zu
|
||||
`SENSITIVE_CUSTOMER_FIELDS` hochgezogen – damit greift der
|
||||
Schutz auch bei der normalen `sanitizeCustomer`-Variante
|
||||
(Admin-Sicht). Auch Pentester-Empfehlung in HOCH-Klasse.
|
||||
- **Live-verifiziert**:
|
||||
* Admin `PUT /customers/3 {firstName:…}` → 0 Leaks bei
|
||||
portalPasswordHash/ResetToken/Expires/MustChange/consentHash/
|
||||
TokenInvalidatedAt; `portalPasswordEncrypted` bleibt für
|
||||
Admin sichtbar (UI-Workflow)
|
||||
* Portal-User `GET /customers/3` → 0 Leaks auch bei
|
||||
portalPasswordEncrypted/notes
|
||||
* `POST /customers` (create) ebenfalls dicht
|
||||
|
||||
- [x] **🛟 Admin-Rescue-Script (PW-Reset direkt in DB + Rate-Limit-Reset)**
|
||||
- Use Case: Admin sperrt sich aus (z.B. `admin@admin.com` ist
|
||||
keine echte E-Mail → Passwort-vergessen-Flow kann keine Mail
|
||||
|
||||
Reference in New Issue
Block a user