[P1 Security] Session Security Hardening – Encryption & Secure Cookies (vibe-kanban 48c2078b)

## Security Audit: Session-Konfiguration härten

### Problem
Die aktuelle `.env.example` hat unsichere Session-Defaults:

```env
SESSION_ENCRYPT=false      # Session-Daten unverschlüsselt in der DB
SESSION_SECURE_COOKIE=     # Nicht gesetzt – Cookie wird auch über HTTP gesendet
SESSION_DOMAIN=null         # Nicht eingeschränkt
```

Da die App eine Custom Nostr-basierte Auth verwendet (`app/Auth/NostrSessionGuard.php`) und der `pubkey` in der Session gespeichert wird, ist die Session ein attraktives Angriffsziel. Unverschlüsselte Sessions in der Datenbank bedeuten, dass ein DB-Leak sofort alle aktiven Sessions kompromittiert.

### Lösung

**1. `.env.example` aktualisieren:**

```env
SESSION_ENCRYPT=true
SESSION_SECURE_COOKIE=true
```

**2. Session-Config in `config/session.php` prüfen:**

Falls `config/session.php` nicht existiert (Laravel 12 Slim-Struktur), muss die Config ggf. mit `php artisan config:publish session` veröffentlicht werden. Prüfe ob die folgenden Werte korrekt gesetzt sind:

```php
'encrypt' => env('SESSION_ENCRYPT', true),        // Default auf true ändern
'secure' => env('SESSION_SECURE_COOKIE', true),    // Default auf true ändern
'http_only' => true,                                // Bereits Standard
'same_site' => 'lax',                               // Bereits Standard
```

**3. Cookie-Sicherheit:**
- `http_only` verhindert JavaScript-Zugriff auf Session-Cookies (Schutz gegen XSS-Cookie-Theft)
- `secure` erzwingt HTTPS-only Übertragung
- `same_site: lax` schützt gegen CSRF bei Top-Level-Navigation

### Betroffene Dateien
- `.env.example` – Default-Werte aktualisieren
- `config/session.php` – Falls vorhanden, Defaults härten. Falls nicht vorhanden, mit `php artisan config:publish session` erstellen und anpassen

### Vorgehen
1. Prüfe ob `config/session.php` existiert (bei Laravel 12 ist es möglicherweise nicht veröffentlicht)
2. Falls nicht vorhanden: `php artisan config:publish session --no-interaction`
3. Sichere Defaults setzen (encrypt=true, secure=true)
4. `.env.example` aktualisieren
5. Einen Pest-Test schreiben, der verifiziert dass Session-Cookies die korrekten Flags haben (secure, httpOnly, sameSite)
6. `vendor/bin/pint --dirty` und `php artisan test --compact`

### Hinweis
- In der lokalen Entwicklung (`APP_ENV=local`) kann `SESSION_SECURE_COOKIE=false` gesetzt werden, damit HTTP funktioniert
- Der Default in der Config sollte aber `true` sein, damit Produktion abgesichert ist
- Die `.env` Datei selbst wird NICHT bearbeitet (nur `.env.example`)

### Akzeptanzkriterien
- `SESSION_ENCRYPT=true` als Default in `.env.example`
- `SESSION_SECURE_COOKIE=true` als Default in `.env.example`
- Session-Config verwendet sichere Defaults
- Tests verifizieren Cookie-Sicherheitsflags
- Lokale Entwicklung bleibt funktional (über `.env` Override)
This commit is contained in:
vk
2026-02-11 23:19:31 +01:00
parent 0639c1a656
commit 058612dbe6
3 changed files with 43 additions and 3 deletions

View File

@@ -34,7 +34,8 @@ DB_PASSWORD_EINUNDZANZIG=secret
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_ENCRYPT=true
SESSION_SECURE_COOKIE=true
SESSION_PATH=/
SESSION_DOMAIN=null

View File

@@ -47,7 +47,7 @@ return [
|
*/
'encrypt' => env('SESSION_ENCRYPT', false),
'encrypt' => env('SESSION_ENCRYPT', true),
/*
|--------------------------------------------------------------------------
@@ -169,7 +169,7 @@ return [
|
*/
'secure' => env('SESSION_SECURE_COOKIE'),
'secure' => env('SESSION_SECURE_COOKIE', true),
/*
|--------------------------------------------------------------------------

View File

@@ -0,0 +1,39 @@
<?php
it('has secure defaults in session config file', function () {
$config = require base_path('config/session.php');
// When no env vars are set, these should default to secure values
expect($config['http_only'])->toBeTrue('http_only should default to true');
expect($config['same_site'])->toBe('lax', 'same_site should default to lax');
});
it('defaults session encryption to true in config', function () {
$configContent = file_get_contents(base_path('config/session.php'));
expect($configContent)->toContain("env('SESSION_ENCRYPT', true)");
});
it('defaults secure cookie to true in config', function () {
$configContent = file_get_contents(base_path('config/session.php'));
expect($configContent)->toContain("env('SESSION_SECURE_COOKIE', true)");
});
it('has secure session defaults in env example', function () {
$envExample = file_get_contents(base_path('.env.example'));
expect($envExample)->toContain('SESSION_ENCRYPT=true');
expect($envExample)->toContain('SESSION_SECURE_COOKIE=true');
});
it('sets httponly and samesite flags on session cookie', function () {
$response = $this->get('/');
$sessionCookie = collect($response->headers->getCookies())
->first(fn ($cookie) => $cookie->getName() === config('session.cookie'));
expect($sessionCookie)->not->toBeNull();
expect($sessionCookie->isHttpOnly())->toBeTrue('Session cookie should be HttpOnly');
expect($sessionCookie->getSameSite())->toBe('lax', 'Session cookie should have SameSite=lax');
});