mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-nostr.git
synced 2026-02-15 03:23:17 +00:00
[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:
@@ -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
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
39
tests/Feature/SessionSecurityTest.php
Normal file
39
tests/Feature/SessionSecurityTest.php
Normal 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');
|
||||
});
|
||||
Reference in New Issue
Block a user