New explanation page covers full session lifecycle: idle/absolute timeouts, remember-token mechanics, frontend keepalive, and cookie attributes. Updates rate limiting docs with remember-token limits and smoke test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.5 KiB
Session-Management
Letzte Aktualisierung: 2026-03-14
Ziel
Vollstaendige Erklaerung des Session-Lifecycle: Wann wird ein User abgemeldet, wann greift der Remember-Token, wie bleiben Frontend und Server synchron.
Session-Lifecycle (Uebersicht)
Login (Passwort / SSO)
│
├─ $_SESSION['session_started_at'] = time()
├─ $_SESSION['session_last_activity'] = time()
└─ Optional: Remember-Token (Cookie, 30 Tage)
│
▼
Jeder Request (web/index.php)
│
├─ Session vorhanden?
│ ├─ JA → Idle-Check + Absolute-Check
│ └─ NEIN → Remember-Cookie vorhanden?
│ ├─ JA → Auto-Login (Token validieren + rotieren)
│ └─ NEIN → Redirect /login
│
├─ authz_version geaendert? → Permissions neu laden
└─ User deaktiviert/geloescht? → Forced Logout
Zwei Timeouts
| Timeout | Default | Bereich | Zuruecksetzbar? | DB-Key |
|---|---|---|---|---|
| Idle | 30 Min | 5 Min – 24 Std | Ja, bei jeder Aktivitaet | session_idle_timeout_minutes |
| Absolute | 8 Std | 1 Std – 72 Std | Nein, nie | session_absolute_timeout_hours |
Pruefung in web/index.php (bei jedem Request):
Idle: (now - last_activity) > idle_timeout → Timeout
Absolute: (now - session_started_at) > absolute_timeout → Timeout
Einer greift → logoutDueToSessionTimeout() → Audit-Event auth.session.timeout → Flash-Message → Redirect /login?return_to=<url>.
Wichtig: Der Absolute-Timeout wird nie zurueckgesetzt, auch nicht durch "Session verlaengern". Er begrenzt die maximale Sitzungsdauer hart.
Frontend-Warning und Keepalive
Quelle: web/js/components/app-session-warning.js
0 Min 28 Min 30 Min
├───────────────┤───────────────┤
Aktiv Warning-Dialog Timeout
(2 Min Countdown)
Interaktions-Tracking
- Events:
click,keydown,scroll,mousemove,touchstart - Throttled auf 30s (kein Overhead bei schnellem Scrollen)
- Setzt nur den JS-Timer zurueck, nicht den Server-Timer
Background-Keepalive
Problem ohne Keepalive: User scrollt 29 Min auf einer Seite → JS zeigt "aktiv", Server sagt "idle".
Loesung: Alle 5 Minuten prueft ein Intervall ob seit dem letzten Sync Interaktion stattfand. Falls ja → POST /admin/session-ping/data → Server-Timer zurueckgesetzt.
| Szenario | Keepalive-Ping? |
|---|---|
| User aktiv (Maus, Scroll, Klick) | Ja, alle 5 Min |
| User wirklich idle | Nein |
| Warning-Dialog offen | Nein |
| Tab im Hintergrund | Nein (keine Events) |
Warning-Dialog
- Erscheint 2 Min vor Idle-Timeout
- Nur bei Idle-Timeout >= 3 Min
- Kann nicht per ESC oder Backdrop geschlossen werden
- Zwei Optionen: Session verlaengern (POST Ping) oder Abmelden (Redirect /logout)
Remember-Token
Quelle: lib/Service/Auth/RememberMeService.php
Token-Struktur
Cookie "remember" = selector:token
(24 hex) (64 hex)
DB: user_remember_tokens
├─ selector → Lookup (UNIQUE Index)
├─ token_hash → SHA-256 (constant-time Verify)
├─ expires_at → Default 30 Tage (konfigurierbar 1-365)
└─ last_used
Selector und Token sind getrennt: Selector fuer schnellen DB-Lookup, Token-Hash fuer timing-sichere Validierung. Kein Klartext-Token in der DB.
Auto-Login-Ablauf
- Kein aktiver Session-User → Remember-Cookie lesen
- Rate-Limit pruefen (IP nicht blockiert?)
- Selector → DB-Lookup
- Token →
hash_equals(SHA256)Verify - User aktiv? Token nicht abgelaufen?
- Session neu aufbauen (User, Permissions, Tenant-Kontext)
- Token rotieren (neuer Hash, neues Expiry)
- Rate-Limit-Counter zuruecksetzen
Token-Rotation bei jedem Auto-Login begrenzt das Fenster bei Cookie-Diebstahl.
Rate Limiting (Remember-Token)
Quelle: lib/Service/Auth/RememberMeRateLimiter.php
- Storage: Memcached (
Cache::add+Cache::increment) - Limit: 5 Fehlversuche pro IP in 15 Minuten
- Counter laeuft automatisch ab (Memcached TTL)
- Fail-open: Bei Memcached-Ausfall wird nicht blockiert
- Erfolgreicher Auto-Login setzt Counter zurueck
Siehe /docs/howto-anfragelimits.md fuer alle Rate-Limits.
Zusammenspiel Absolute Timeout + Remember-Token
Login → 8h Absolute Timeout → Session endet
│
Remember-Token?
├─ JA → Neue Session (neuer 8h-Timer!)
└─ NEIN → Login-Seite
Solange der Remember-Token lebt (Default 30 Tage), bekommt der User nach Ablauf des Absolute-Timeout automatisch eine neue Session. Der Uebergang ist nahtlos (kein Flash, kein Login-Screen).
Das bedeutet: Mit aktivem Remember-Token ist die effektive Session-Dauer nicht 8 Stunden, sondern bis zu 30 Tage. Das ist by-design, sollte aber bei Compliance-Anforderungen (z. B. echte Re-Authentifizierung nach X Stunden) beruecksichtigt werden.
Cookie-Attribute
| Attribut | Wert | Grund |
|---|---|---|
httponly |
true |
Kein JS-Zugriff (XSS-Schutz) |
samesite |
Lax |
CSRF-Schutz bei Cross-Site-Navigation |
secure |
dynamisch | true bei HTTPS, false bei HTTP (Dev) |
path |
/ |
Gueltig fuer gesamte Domain |
Das Secure-Flag wird automatisch anhand des Protokolls gesetzt (RequestRuntime::isSecure()). In Produktion muss HTTPS ueber Nginx erzwungen werden (Redirect 80→443 + HSTS).
Audit-Events
| Event | Ausloeser |
|---|---|
auth.login.success |
Erfolgreicher Login (Passwort/SSO) |
auth.login.failed |
Fehlgeschlagener Login |
auth.logout |
Manueller Logout |
auth.session.timeout |
Idle- oder Absolute-Timeout |
Beteiligte Dateien
| Komponente | Pfad |
|---|---|
| Timeout-Pruefung | web/index.php |
| AuthService | lib/Service/Auth/AuthService.php |
| RememberMeService | lib/Service/Auth/RememberMeService.php |
| RememberMeRateLimiter | lib/Service/Auth/RememberMeRateLimiter.php |
| Session-Settings | lib/Service/Settings/SettingsSessionGateway.php |
| Frontend-Warning | web/js/components/app-session-warning.js |
| Session-Ping | pages/admin/session-ping/data().php |
| Login-Action | pages/auth/login().php |
| SSO-Callback | pages/auth/microsoft/callback().php |
Vertiefung
/docs/explanation-sicherheitsmodell.md/docs/howto-anfragelimits.md/docs/howto-auth-sso-smoke-test.md/docs/reference-konfiguration.md