# Security-Review vor 1.0.0 > 📌 **Diese Datei dokumentiert nur die ersten 2 Runden ausführlich.** > Die vollständige Hardening-Story über alle **8 Runden** inkl. Live-Test- > Tabellen findest du in **[SECURITY-HARDENING.md](./SECURITY-HARDENING.md)**. > **Version 2** – dieser Review wurde in 2 Runden durchgeführt. > Runde 1: erste kritische Findings (CORS, Helmet, JWT-Fallback, grobes IDOR, XSS, Data Exposure). > Runde 2 (weiter unten): **Deep-Dive** mit parallelen Audit-Agents – fand weitere IDOR-Stellen, Mass Assignment, Zip-Slip, Path-Traversal. Systematischer Review des Codebase mit Fokus auf Produktions-Hardening vor öffentlichem Deployment (hinter HTTPS-Proxy). ## Gefundene Probleme & Fixes ### 🔴 KRITISCH (sofort gefixt) #### 1. CORS komplett offen **Vorher:** `app.use(cors())` – jede Origin darf Requests senden. **Risiko:** Fremde Websites können bei eingeloggtem User Requests mit dessen JWT durchführen (wenn Token in Cookies wäre – bei localStorage weniger relevant, aber trotzdem schlechte Praxis). **Fix:** CORS nur für explizit konfigurierte Origins (via `CORS_ORIGINS` ENV), in Production per Default komplett aus (Frontend läuft unter gleicher Origin). #### 2. Keine Security-Headers (Helmet fehlt) **Vorher:** Keine HTTP-Security-Headers gesetzt. **Risiko:** XSS, Clickjacking, MIME-Sniffing, Missing HSTS. **Fix:** `helmet`-Middleware aktiviert – setzt automatisch: X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS (in HTTPS), Cross-Origin-Resource-Policy. #### 3. JWT-Fallback-Secret **Vorher:** `jwt.verify(token, process.env.JWT_SECRET || 'fallback-secret')` **Risiko:** Wenn `.env` kaputt ist oder Secret leer → bekannter String "fallback-secret" → **Tokens können gefälscht werden!** **Fix:** Beim Server-Start wird geprüft, dass JWT_SECRET mindestens 32 Zeichen lang und ENCRYPTION_KEY exakt 64 Hex-Zeichen hat. Sonst Abbruch mit klarer Fehlermeldung. Fallback wurde aus dem Code entfernt. #### 4. IDOR bei sensiblen Contract-Endpoints **Vorher:** Portal-Kunden haben `contracts:read` Permission → können über geratene IDs auf **fremde** Daten zugreifen: - `GET /contracts/:id/password` → Passwort im Klartext - `GET /contracts/simcard/:id/credentials` → PIN/PUK - `GET /contracts/:id/internet-credentials` → Internet-Passwort - `GET /contracts/phonenumber/:id/sip-credentials` → SIP-Passwort - `GET /contracts/:id/documents` → Vertragsdokumente - `GET /contracts/:id/invoices` → Rechnungen - `POST /contracts/:id/invoices` → Rechnung zu fremdem Vertrag hinzufügen **Fix:** Neuer Helper `canAccessContract()` in `backend/src/utils/accessControl.ts`. Wird in allen sensiblen Endpoints aufgerufen und prüft: - Mitarbeiter/Admin → OK - Portal-Kunde + eigener Vertrag → OK - Portal-Kunde + vertretener Kunde MIT gültiger Vollmacht → OK - Sonst 403 Forbidden #### 5. XSS via Email-Body **Vorher:** `
` **Risiko:** Ein Angreifer sendet Mail mit `` in HTML-Body senden, im Email-Client öffnen → kein Alert 3. **Rate-Limit-Tests:** 11x falsch einloggen → muss blocken 4. **Password-Reset-Tests:** Reset-Link 2x nutzen → zweites Mal fehlschlägt ## Übersicht der Code-Änderungen | Datei | Änderung | |---|---| | `backend/src/index.ts` | Helmet, CORS-Config, Body-Limit, ENV-Check beim Start | | `backend/src/middleware/auth.ts` | JWT-Fallback raus, Portal-Token-Invalidation | | `backend/src/services/auth.service.ts` | JWT-Fallback raus, `portalTokenInvalidatedAt` setzen | | `backend/src/utils/accessControl.ts` | **NEU** – `canAccessContract`, `canAccessCustomer` | | `backend/src/utils/sanitize.ts` | **NEU** – Sanitizer für Customer/User | | `backend/src/controllers/contract.controller.ts` | IDOR-Schutz in 5 Endpoints | | `backend/src/controllers/invoice.controller.ts` | IDOR-Schutz in 2 Endpoints | | `backend/src/controllers/customer.controller.ts` | Sanitizer in getCustomer/getCustomers | | `backend/prisma/schema.prisma` | `Customer.portalTokenInvalidatedAt` | | `frontend/src/components/email/EmailDetail.tsx` | DOMPurify für htmlBody |