Security-Hardening: IDOR-Fixes, XSS-Sanitizer, CORS+Helmet, Data-Exposure

Umfassender Security-Review vor öffentlichem Deployment.
Detaillierter Report in docs/SECURITY-REVIEW.md.

🔴 KRITISCHE FIXES:

1. CORS offen → jetzt nur explizite Origins (via CORS_ORIGINS env),
   in Production per default komplett aus (gleiche Origin erzwingt Browser).

2. Keine Security-Headers → helmet-Middleware hinzugefügt.
   X-Frame-Options, X-Content-Type-Options, HSTS, Referrer-Policy, CORP.

3. JWT-Fallback-Secret entfernt. Beim Server-Start wird jetzt geprüft ob
   JWT_SECRET (min 32 Zeichen) und ENCRYPTION_KEY (exakt 64 Hex) gesetzt sind,
   sonst Fail-Fast mit klarer Fehlermeldung.

4. IDOR bei 7 Contract-Endpoints. Portal-Kunden mit 'contracts:read'
   konnten über geratene IDs fremde Daten abrufen (Passwort, SIM-PIN/PUK,
   Internet-Zugangsdaten, SIP-Credentials, Vertragsdokumente, Rechnungen).
   Neuer Helper canAccessContract() in utils/accessControl.ts in allen
   betroffenen Endpoints eingebaut. Prüft Vertrag-Besitzer + Vollmachten.

5. XSS via Email-Body. email.htmlBody wurde ungefiltert via
   dangerouslySetInnerHTML gerendert. Angreifer konnte Mail mit <script>
   schicken → Token-Diebstahl aus localStorage. Jetzt mit DOMPurify
   sanitized: verbietet script/iframe/form/inline-handler, erlaubt
   normale Formatierung + Bilder.

6. Customer-API leakte sensible Felder:
   - portalPasswordHash (bcrypt-Hash)
   - portalPasswordEncrypted (symmetrisch, mit ENCRYPTION_KEY entschlüsselbar)
   - portalPasswordResetToken (gültig 2h)
   Neuer Sanitizer in utils/sanitize.ts, angewendet in getCustomer/getCustomers.
   Admin mit customers:update darf portalPasswordEncrypted sehen (für UI-Anzeige),
   alle anderen Rollen nicht.

🟡 WICHTIGE FIXES:

7. Portal-JWT-Invalidation nach Passwort-Reset. Neues Feld
   Customer.portalTokenInvalidatedAt, wird beim Reset auf now() gesetzt.
   Auth-Middleware prüft Portal-Sessions dagegen. Alte Sessions werden
   dadurch invalidiert.

8. express.json() mit 5 MB Size-Limit (statt Default 100 KB unklar).

Neue Files:
- backend/src/utils/accessControl.ts - IDOR-Schutz
- backend/src/utils/sanitize.ts - Response-Sanitizer
- docs/SECURITY-REVIEW.md - vollständiger Report + Deployment-Checkliste

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 22:06:16 +02:00
parent 8fc050a282
commit 1c46d7345c
14 changed files with 520 additions and 29 deletions
+14
View File
@@ -97,6 +97,20 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
- [x] **🛡️ Security-Review + Hardening vor Production-Deployment**
- Vollständiger Review aller kritischen Bereiche, dokumentiert in **[docs/SECURITY-REVIEW.md](../docs/SECURITY-REVIEW.md)**
- **6 kritische Findings gefixt:**
- CORS offen → explizit konfigurierbar über `CORS_ORIGINS`
- Helmet (Security-Headers) hinzugefügt
- JWT-Fallback-Secret entfernt, ENV-Pflicht-Check beim Start
- IDOR bei 7 sensiblen Contract-Endpoints (Portal-Kunden konnten fremde Credentials abrufen)
- XSS via Email-Body (DOMPurify als Sanitizer)
- Customer-API leakte Passwort-Hashes + Reset-Tokens
- **2 wichtige Findings gefixt:**
- Portal-JWT-Invalidation nach Passwort-Reset (`Customer.portalTokenInvalidatedAt`)
- Body-Size-Limit auf 5 MB
- Deployment-Checkliste dokumentiert (neue Secrets generieren, HSTS, DB-User-Rechte, Backup-Cron)
- [x] **🎉 Version 1.0.0 Feinschliff: Passwort-Reset + Rate-Limiting + Auto-Geburtstagsgrüße**
- **Passwort vergessen-Flow** (Login → "Passwort vergessen?" Link)
- Email-Reset-Token mit 2h Gültigkeit (kryptografisch sicher: 32 Byte Random)