Security-Hardening Runde 8: Cockpit-IDOR (Portal sah ALLE Kunden)

Pentest Runde 4 – HOCH:
GET /api/contracts/cockpit gab Portal-Usern mit contracts:read
die kompletten Vertrags-, Ausweis- und Zählerstand-Daten ALLER
Kunden zurück. Realer Angriff erfolgreich durchgespielt.

Fix:
contractCockpitService.getCockpitData({ customerIds? }) – wenn
gesetzt, werden ALLE internen Queries (Contract, CustomerConsent
GRANTED/WITHDRAWN, IdentityDocument-Expiry, MeterReading-Reported)
auf diese Customer-IDs eingeschränkt.

Controller getCockpit ermittelt customerIds analog getContracts:
- isCustomerPortal → [eigene, ...vertretene mit Vollmacht]
- sonst (Mitarbeiter/Admin) → undefined (alle Kunden)

Live-verifiziert:
- Admin: 17 Verträge über 3 Kunden (Baseline)
- Portal-User Customer 1: 12 Verträge, alle mit customerId=1
- Portal-User Customer 3: 3 Verträge, alle mit customerId=3
- 0 fremde Verträge in Portal-Responses

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 19:55:38 +02:00
parent a7d12b8540
commit 75c833500e
3 changed files with 59 additions and 10 deletions
+19
View File
@@ -97,6 +97,25 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
- [x] **🚨 Pentest Runde 4 HOCH: Cockpit-IDOR (Portal-User sah ALLE Kunden)**
- **Realer Angriff**: Portal-User Max bekam mit seinem Token
`GET /api/contracts/cockpit` → komplette Vertragsliste ALLER
Kunden (Customer-Namen, Vertragsnummern, Statūs).
- **Root Cause**: `contractCockpitService.getCockpitData()` filterte
nicht nach Customer, weil das Cockpit ursprünglich nur für Admins
gedacht war. Die `contracts:read`-Permission haben aber auch
Portal-User → Endpoint war erreichbar.
- **Fix**: Service-Signatur erweitert auf
`getCockpitData({ customerIds? })`. Wenn `customerIds` gesetzt
sind, werden Haupt-Vertrags-Query, Consent-Maps, Ausweis-
Warnungen und gemeldete Zählerstände allesamt auf diese IDs
eingeschränkt. Controller bestimmt `customerIds` analog zu
`getContracts`: bei `isCustomerPortal` → eigene + vertretene
Kunden (nur mit Vollmacht); sonst undefined (= alle).
- **Live-verifiziert**: Admin sieht 17 Verträge (3 Kunden);
Portal-User Customer 1 sieht 12 (nur seine); Portal-User
Customer 3 sieht 3 (nur seine); 0 Leaks.
- [x] **🚨 Pentest Runde 3 drei Findings gefixt**
- **KRITISCH `POST /api/developer/setup` ohne Auth (Privilege
Escalation)**: Endpoint war komplett ohne Authentifizierung