diff --git a/docs/anleitungen/SECURITY.md b/docs/anleitungen/SECURITY.md new file mode 100644 index 0000000..a577c81 --- /dev/null +++ b/docs/anleitungen/SECURITY.md @@ -0,0 +1,264 @@ +# Security-Richtlinien - Payload CMS Multi-Tenant + +> Letzte Aktualisierung: 08.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 + +--- + +## Änderungshistorie + +| Datum | Änderung | +|-------|----------| +| 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 | diff --git a/docs/anleitungen/TODO.md b/docs/anleitungen/TODO.md index dd87794..51378b6 100644 --- a/docs/anleitungen/TODO.md +++ b/docs/anleitungen/TODO.md @@ -382,9 +382,9 @@ - [x] SEO_ERWEITERUNG.md (SEO Features) - [x] ANALYTICS_IMPLEMENTATION_GUIDE.md (Umami & Google Ads) - [x] Techstack_Dokumentation_12_2025.md (Infrastruktur & Deployment) +- [x] SECURITY.md (Sicherheitsrichtlinien) (Erledigt: 08.12.2025) - [ ] DEPLOYMENT.md (Deployment-Prozess) - [ ] FRONTEND_INTEGRATION.md (Next.js Guide) -- [ ] SECURITY.md (Sicherheitsrichtlinien) --- @@ -419,11 +419,11 @@ ### Nächste Schritte (Priorisiert) -1. **[KRITISCH]** AuditLogs Collection implementieren +1. ~~**[KRITISCH]** AuditLogs Collection implementieren~~ ✅ Erledigt 2. **[KRITISCH]** Automatisierte Backups einrichten 3. **[HOCH]** Full-Text-Search aktivieren (USE_FTS=true) -4. **[HOCH]** Rate-Limits auf Redis migrieren -5. **[MITTEL]** CI/CD Pipeline mit GitHub Actions +4. **[HOCH]** Rate-Limits auf Redis migrieren (In-Memory-Fallback funktioniert) +5. ~~**[MITTEL]** CI/CD Pipeline mit GitHub Actions~~ ✅ security.yml erstellt 6. **[MITTEL]** Frontend-Entwicklung starten 7. **[NIEDRIG]** Admin UX Verbesserungen