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:
@@ -15,6 +15,14 @@ const SENSITIVE_CUSTOMER_FIELDS = [
|
||||
// braucht, holt ihn über GET /gdpr/customer/:id/consent-status (eigener
|
||||
// Endpoint mit canAccessCustomer-Check). Pentest Runde 5 (2026-05-16).
|
||||
'consentHash',
|
||||
// Session-/OTP-State – Pentest Runde 15 (2026-05-18, 20.4 HOCH): zeigt
|
||||
// einem externen Beobachter, ob ein Kunde gerade im OTP-Flow ist und
|
||||
// wann zuletzt seine Tokens invalidiert wurden. Reiner Info-Leak ohne
|
||||
// Auth-Bypass, aber unnötig. Wenn Admin diese Information legitim
|
||||
// braucht (z.B. UI-Hinweis "OTP wurde noch nicht eingelöst"), führen
|
||||
// wir bei Bedarf einen eigenen Endpoint ein.
|
||||
'portalPasswordMustChange',
|
||||
'portalTokenInvalidatedAt',
|
||||
] as const;
|
||||
|
||||
// Zusätzliche Felder die Portal-User nicht in ihrer Customer-Response sehen
|
||||
@@ -22,9 +30,9 @@ const SENSITIVE_CUSTOMER_FIELDS = [
|
||||
// unnötige Informationsleckage über den DB-Aufbau.
|
||||
// Pentest Runde 7 (2026-05-17), MEDIUM.
|
||||
const PORTAL_HIDDEN_CUSTOMER_FIELDS = [
|
||||
'portalTokenInvalidatedAt',
|
||||
// portalTokenInvalidatedAt + portalPasswordMustChange sind jetzt in
|
||||
// SENSITIVE_CUSTOMER_FIELDS (immer raus), nicht mehr nur für Portal.
|
||||
'portalLastLogin',
|
||||
'portalPasswordMustChange',
|
||||
'lastBirthdayGreetingYear',
|
||||
// privacyPolicyPath etc. sind interne Datei-Pfade – Portal nutzt
|
||||
// dedizierte PDF-Endpoints, nicht den Pfad direkt
|
||||
|
||||
Reference in New Issue
Block a user