# Security-Richtlinien - Payload CMS Multi-Tenant > Letzte Aktualisierung: 09.12.2025 ## Übersicht Dieses Dokument beschreibt die implementierten Sicherheitsmaßnahmen für das Payload CMS Multi-Tenant-Projekt. --- ## Security-Module Alle Security-Funktionen befinden sich in `src/lib/security/`: | Modul | Datei | Zweck | |-------|-------|-------| | Rate Limiter | `rate-limiter.ts` | Schutz vor API-Missbrauch | | IP Allowlist | `ip-allowlist.ts` | IP-basierte Zugriffskontrolle | | CSRF Protection | `csrf.ts` | Cross-Site Request Forgery Schutz | | Data Masking | `data-masking.ts` | Sensitive Daten in Logs maskieren | ### Rate Limiter **Vordefinierte Limiter:** | Name | Limit | Fenster | Verwendung | |------|-------|---------|------------| | `publicApiLimiter` | 60 Requests | 1 Minute | Öffentliche API-Endpunkte | | `authLimiter` | 5 Requests | 15 Minuten | Login-Versuche | | `emailLimiter` | 10 Requests | 1 Minute | E-Mail-Versand | | `searchLimiter` | 30 Requests | 1 Minute | Suche & Posts-API | | `formLimiter` | 5 Requests | 10 Minuten | Formular-Submissions | **Verwendung:** ```typescript import { searchLimiter, rateLimitHeaders } from '@/lib/security' export async function GET(req: NextRequest) { const ip = getClientIp(req.headers) const rateLimit = await searchLimiter.check(ip) if (!rateLimit.allowed) { return NextResponse.json( { error: 'Too many requests' }, { status: 429, headers: rateLimitHeaders(rateLimit, 30) } ) } // ... } ``` **Redis-Support:** - Automatischer Fallback auf In-Memory-Store wenn Redis nicht verfügbar - Für verteilte Systeme: Redis via `REDIS_URL` konfigurieren ### IP Allowlist/Blocklist **Environment-Variablen:** | Variable | Zweck | Format | |----------|-------|--------| | `BLOCKED_IPS` | Globale Blocklist | IP, CIDR, Wildcard | | `SEND_EMAIL_ALLOWED_IPS` | E-Mail-Endpoint Allowlist | IP, CIDR, Wildcard | | `ADMIN_ALLOWED_IPS` | Admin-Panel Allowlist | IP, CIDR, Wildcard | | `WEBHOOK_ALLOWED_IPS` | Webhook-Endpoint Allowlist | IP, CIDR, Wildcard | **Unterstützte Formate:** ```bash # Einzelne IP BLOCKED_IPS=192.168.1.100 # Mehrere IPs BLOCKED_IPS=192.168.1.100,10.0.0.50 # CIDR-Notation BLOCKED_IPS=10.0.0.0/24 # Wildcard BLOCKED_IPS=192.168.* # Kombiniert BLOCKED_IPS=10.0.0.0/8,192.168.1.50,172.16.* ``` **Verwendung:** ```typescript import { validateIpAccess } from '@/lib/security' const ipCheck = validateIpAccess(req, 'sendEmail') if (!ipCheck.allowed) { return NextResponse.json( { error: 'Access denied', reason: ipCheck.reason }, { status: 403 } ) } ``` ### CSRF Protection **Pattern:** Double Submit Cookie **Token-Endpoint:** `GET /api/csrf-token` **Frontend-Integration:** ```typescript // 1. Token abrufen const res = await fetch('/api/csrf-token', { credentials: 'include' }) const { csrfToken } = await res.json() // 2. Bei Mutations mitschicken await fetch('/api/send-email', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrfToken, }, body: JSON.stringify({ /* ... */ }) }) ``` **Server-seitige Validierung:** ```typescript import { validateCsrf } from '@/lib/security' const csrf = validateCsrf(req) if (!csrf.valid) { return NextResponse.json( { error: 'CSRF validation failed' }, { status: 403 } ) } ``` **Bypass für Server-to-Server:** - Requests ohne `Origin`/`Referer` Header werden als Server-to-Server behandelt - API-Key-basierte Authentifizierung umgeht CSRF-Check ### Data Masking **Automatisch maskierte Felder:** - password, passwd, pwd - token, accessToken, refreshToken - apiKey, api_key - secret, clientSecret - credentials - privateKey, private_key - smtpPassword, smtp_pass **Verwendung:** ```typescript import { maskObject, createSafeLogger } from '@/lib/security' // Objekte maskieren const safeData = maskObject(sensitiveObject) // Safe Logger verwenden const logger = createSafeLogger('MyModule') logger.info('User action', { password: 'secret' }) // Output: { password: '[REDACTED]' } ``` **Pattern-Erkennung:** - JWT Tokens: Header bleibt, Payload/Signature maskiert - Connection Strings: Passwort maskiert - Private Keys: Komplett ersetzt --- ## Pre-Commit Hook Secret Detection bei jedem Commit via `scripts/detect-secrets.sh`: **Installation:** ```bash ln -sf ../../scripts/detect-secrets.sh .git/hooks/pre-commit ``` **Erkannte Patterns:** - API Keys und Tokens - AWS Credentials - Private Keys - Passwörter in Code - SMTP Credentials - Database Connection Strings - JWT Tokens - Webhook URLs (Slack, Discord) - GitHub/SendGrid/Stripe Tokens **Ignorierte Dateien:** - `*.min.js`, `*.min.css` - `package-lock.json`, `pnpm-lock.yaml` - `*.md`, `*.txt` - `*.example`, `*.sample` - `*.spec.ts`, `*.test.ts` (Test-Dateien) --- ## CI/CD Security **.github/workflows/security.yml:** | Job | Prüfung | |-----|---------| | `secrets` | Gitleaks Secret Scanning | | `dependencies` | npm audit, Dependency Check | | `codeql` | Static Code Analysis | | `security-tests` | 143 Security Unit & Integration Tests | --- ## Test Suite **Ausführung:** ```bash # Alle Security-Tests pnpm test:security # Nur Unit-Tests pnpm test:unit ``` **Abdeckung:** | Test-Datei | Tests | Bereich | |------------|-------|---------| | `rate-limiter.unit.spec.ts` | 21 | Limiter, Tracking, Reset | | `csrf.unit.spec.ts` | 34 | Token, Validierung, Origin | | `ip-allowlist.unit.spec.ts` | 29 | CIDR, Wildcards, Endpoints | | `data-masking.unit.spec.ts` | 41 | Felder, Patterns, Rekursion | | `security-api.int.spec.ts` | 18 | API-Integration | --- ## Empfehlungen ### Production Checklist - [ ] Alle `BLOCKED_IPS` für bekannte Angreifer setzen - [ ] `SEND_EMAIL_ALLOWED_IPS` auf vertrauenswürdige IPs beschränken - [ ] `ADMIN_ALLOWED_IPS` auf Office/VPN-IPs setzen - [ ] Redis für verteiltes Rate Limiting konfigurieren - [ ] CSRF_SECRET in .env setzen (min. 32 Zeichen) - [ ] Pre-Commit Hook aktivieren ### Monitoring - Rate Limit Violations loggen (429 Responses) - CSRF Validation Failures überwachen - Blocked IP Attempts tracken - Login-Fehlversuche (authLimiter) alertieren --- ## Custom Login Route Das Admin Panel verwendet eine Custom Login Route (`src/app/(payload)/api/users/login/route.ts`) mit folgenden Features: - **Audit-Logging:** Jeder Login-Versuch wird in AuditLogs protokolliert - **Rate-Limiting:** 5 Versuche pro 15 Minuten (authLimiter) - **Content-Type Support:** - JSON (`application/json`) - FormData mit `_payload` JSON-Feld (Payload Admin Panel Format) - Standard FormData (`multipart/form-data`) - URL-encoded (`application/x-www-form-urlencoded`) **Sicherheitsaspekte:** - Passwort wird nie in Logs/Responses exponiert - Fehlgeschlagene Login-Versuche werden mit IP und User-Agent geloggt - Rate-Limiting verhindert Brute-Force-Angriffe --- ## Änderungshistorie | Datum | Änderung | |-------|----------| | 09.12.2025 | Custom Login Route Dokumentation, multipart/form-data _payload Support | | 08.12.2025 | Security Test Suite (143 Tests) | | 07.12.2025 | Rate Limiter, CSRF, IP Allowlist, Data Masking | | 07.12.2025 | Pre-Commit Hook, GitHub Actions Workflow |