Files
michaelschiemer/docs/framework/csrf-protection.md
2025-11-24 21:28:25 +01:00

366 lines
8.9 KiB
Markdown

# CSRF Protection System
## Übersicht
Das CSRF (Cross-Site Request Forgery) Protection System bietet robusten Schutz gegen CSRF-Angriffe durch:
- **Atomare Session-Updates**: Verhindert Race Conditions bei parallelen Requests
- **Vereinfachte Token-Generierung**: Immer neue Token, keine Wiederverwendung
- **Robuste HTML-Verarbeitung**: DOM-basierte Token-Ersetzung mit Regex-Fallback
- **Einheitliche API**: Konsistente Endpunkte für PHP und JavaScript
## Architektur
### Komponenten
1. **CsrfProtection**: Verwaltet Token-Generierung und Validierung
2. **SessionManager**: Bietet atomare Session-Updates mit Locking
3. **FormDataResponseProcessor**: Ersetzt Token-Platzhalter in HTML
4. **CsrfMiddleware**: Validiert Token bei state-changing Requests
5. **API Controllers**: Bereitstellen Token-Endpunkte für JavaScript
### Session-Locking
Das System verwendet Session-Locking, um Race Conditions zu verhindern:
- **FileSessionStorage**: Datei-basiertes Locking mit `flock()`
- **RedisSessionStorage**: Redis `SET NX EX` für atomares Locking
- **InMemorySessionStorage**: In-Memory-Locking für Tests
### Optimistic Locking
SessionData verwendet Versionsnummern für Optimistic Locking:
- Jede Änderung inkrementiert die Version
- Bei Konflikten wird automatisch retried
- Verhindert Datenverlust bei parallelen Updates
## Token-Generierung
### Vereinfachte Strategie
**Wichtig**: Das System generiert **immer neue Token** - keine Wiederverwendung.
```php
// Generiert immer einen neuen Token
$token = $session->csrf->generateToken($formId);
```
### Token-Verwaltung
- **Maximal 3 Token pro Form-ID**: Älteste werden automatisch entfernt
- **Token-Lifetime**: 2 Stunden (7200 Sekunden)
- **Re-Submit Window**: 30 Sekunden für erneute Submissions
- **Automatisches Cleanup**: Abgelaufene Token werden entfernt
### Token-Format
- **Länge**: 64 Zeichen
- **Format**: Hexadezimal (0-9, a-f)
- **Beispiel**: `f677a410facd19e4e004e41e24fa1c8abbe2379a91abcf8642de23a6988ba8b`
## HTML-Verarbeitung
### DOM-basierte Ersetzung
Der `FormDataResponseProcessor` verwendet DOM-basierte Verarbeitung für robuste Token-Ersetzung:
```php
// Automatische Ersetzung von Platzhaltern
$html = $processor->process($html, $session);
```
### Platzhalter-Format
```html
<input type="hidden" name="_token" value="___TOKEN_FORMID___">
```
### Fallback-Mechanismus
Bei DOM-Parsing-Fehlern fällt das System automatisch auf Regex-basierte Ersetzung zurück.
## API-Endpunkte
### Token-Generierung
**GET/POST `/api/csrf/token`**
Generiert einen neuen CSRF-Token für eine Form.
**Parameter:**
- `action` (optional): Form-Action URL (Standard: `/`)
- `method` (optional): HTTP-Methode (Standard: `post`)
- `form_id` (optional): Explizite Form-ID
**Response:**
```json
{
"form_id": "form_abc123def456",
"token": "64-character-hex-token",
"expires_in": 7200,
"headers": {
"X-CSRF-Form-ID": "form_abc123def456",
"X-CSRF-Token": "64-character-hex-token"
}
}
```
### Token-Refresh
**GET `/api/csrf/refresh`**
Generiert einen neuen Token für eine bestehende Form-ID.
**Parameter:**
- `form_id` (erforderlich): Form-ID
**Response:**
```json
{
"form_id": "form_abc123def456",
"token": "64-character-hex-token",
"expires_in": 7200,
"headers": {
"X-CSRF-Form-ID": "form_abc123def456",
"X-CSRF-Token": "64-character-hex-token"
}
}
```
### Token-Informationen
**GET `/api/csrf/info`**
Gibt Informationen über aktive Token zurück.
**Parameter:**
- `form_id` (erforderlich): Form-ID
**Response:**
```json
{
"form_id": "form_abc123def456",
"active_tokens": 2,
"max_tokens_per_form": 3,
"token_lifetime_seconds": 7200,
"resubmit_window_seconds": 30
}
```
## JavaScript-Integration
### CsrfManager
Der `CsrfManager` verwaltet Token automatisch:
```javascript
import { CsrfManager } from './modules/security/CsrfManager.js';
const csrfManager = CsrfManager.create({
endpoint: '/api/csrf/token',
autoRefresh: true,
refreshInterval: 30 * 60 * 1000 // 30 Minuten
});
// Token abrufen
const token = csrfManager.getToken();
// Token-Header für Requests
const headers = csrfManager.getTokenHeader();
```
### Manuelle Token-Anfrage
```javascript
// Token für spezifische Form generieren
const response = await fetch('/api/csrf/token?action=/submit&method=post');
const data = await response.json();
const token = data.token;
const formId = data.form_id;
```
### AJAX-Requests
```javascript
// Token in Request-Body
fetch('/api/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Form-ID': formId,
'X-CSRF-Token': token
},
body: JSON.stringify({
_form_id: formId,
_token: token,
// ... weitere Daten
})
});
```
## Validierung
### Middleware
Die `CsrfMiddleware` validiert automatisch Token für:
- POST Requests
- PUT Requests
- DELETE Requests
- PATCH Requests
GET Requests werden nicht validiert.
### Validierungsprozess
1. **Token-Extraktion**: Aus Request-Body oder Headers
2. **Form-ID-Extraktion**: Aus Request-Body oder Headers
3. **Session-Lookup**: Token in Session suchen
4. **Validierung**: Token-Match und Expiration prüfen
5. **Markierung**: Token als verwendet markieren
### Fehlerbehandlung
Bei Validierungsfehlern wird eine `CsrfValidationFailedException` geworfen mit:
- Fehlgrund (missing token, invalid token, expired, etc.)
- Session-ID
- Anzahl verfügbarer Token
- Liste verfügbarer Form-IDs
## Best Practices
### Form-IDs
- Verwende konsistente Form-IDs für dieselben Formulare
- Form-IDs werden automatisch aus Action und Method generiert
- Explizite Form-IDs können über `form_id` Parameter gesetzt werden
### Token-Refresh
- Token sollten vor Ablauf erneuert werden
- Automatischer Refresh alle 30 Minuten empfohlen
- Bei langen Formularen manuell vor Submit refreshen
### Fehlerbehandlung
```php
try {
// Form-Verarbeitung
} catch (CsrfValidationFailedException $e) {
// Token ungültig - Benutzer sollte Seite neu laden
return redirect()->back()->with('error', 'Session expired. Please try again.');
}
```
### Testing
```php
// Token generieren
$token = $session->csrf->generateToken('test-form');
// Token validieren
$isValid = $session->csrf->validateToken('test-form', $token);
// Mit Debug-Informationen
$result = $session->csrf->validateTokenWithDebug('test-form', $token);
if (!$result['valid']) {
$reason = $result['debug']['reason'];
// ...
}
```
## Troubleshooting
### Token wird nicht akzeptiert
1. **Prüfe Token-Länge**: Muss genau 64 Zeichen sein
2. **Prüfe Form-ID**: Muss mit generierter Form-ID übereinstimmen
3. **Prüfe Session**: Token muss in Session vorhanden sein
4. **Prüfe Expiration**: Token darf nicht abgelaufen sein
### Race Conditions
Das System verwendet atomare Session-Updates, um Race Conditions zu verhindern. Bei Problemen:
1. Prüfe Session-Storage-Konfiguration
2. Prüfe Locking-Mechanismus (File/Redis)
3. Prüfe Logs für Version-Conflicts
### HTML-Verarbeitung
Bei Problemen mit Token-Ersetzung:
1. Prüfe Platzhalter-Format: `___TOKEN_FORMID___`
2. Prüfe HTML-Struktur (DOM-Parsing kann bei malformed HTML fehlschlagen)
3. Prüfe Logs für Fallback auf Regex
## Migration
### Von altem System
Das neue System ist vollständig kompatibel mit dem alten System:
- Alte Token werden weiterhin akzeptiert
- Alte API-Endpunkte funktionieren weiterhin
- Keine Breaking Changes
### Neue Features nutzen
1. Verwende `/api/csrf/token` statt `/api/csrf-token`
2. Nutze atomare Session-Updates für kritische Operationen
3. Verwende DOM-basierte HTML-Verarbeitung (automatisch)
## Performance
### Optimierungen
- **Token-Cleanup**: Automatisch nach 5 Minuten
- **Maximal 3 Token**: Begrenzt Session-Größe
- **Locking-Timeout**: 5 Sekunden Standard-Timeout
- **Optimistic Locking**: Reduziert Lock-Contention
### Monitoring
- Token-Anzahl pro Form-ID überwachen
- Session-Lock-Contention überwachen
- Token-Validierungs-Fehlerrate überwachen
## Sicherheit
### Schutz-Mechanismen
1. **Token-Rotation**: Neue Token nach jeder Generierung
2. **Expiration**: Token laufen nach 2 Stunden ab
3. **Single-Use**: Token können innerhalb von 30 Sekunden wiederverwendet werden
4. **Session-Binding**: Token sind an Session gebunden
### Angriffs-Vektoren
Das System schützt gegen:
- **CSRF-Angriffe**: Token-Validierung verhindert unautorisierte Requests
- **Token-Replay**: Expiration und Single-Use verhindern Replay
- **Session-Hijacking**: Session-Binding verhindert Token-Diebstahl
## Referenz
### Klassen
- `App\Framework\Http\Session\CsrfProtection`
- `App\Framework\Http\Session\SessionManager`
- `App\Framework\View\Response\FormDataResponseProcessor`
- `App\Framework\Http\Middlewares\CsrfMiddleware`
- `App\Application\Api\CsrfController`
- `App\Application\Controller\CsrfController`
### Konstanten
- `CsrfProtection::TOKEN_LIFETIME` = 7200 (2 Stunden)
- `CsrfProtection::MAX_TOKENS_PER_FORM` = 3
- `CsrfProtection::RE_SUBMIT_WINDOW` = 30 (Sekunden)