feat(security): implement session management features including idle timeout, keepalive, and secure logout
This commit is contained in:
+38
-4
@@ -10,6 +10,7 @@ if (basename($_SERVER['SCRIPT_FILENAME'] ?? '') === 'auth.php') {
|
||||
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
require_once __DIR__ . '/totp.php';
|
||||
require_once __DIR__ . '/settings.php';
|
||||
|
||||
/**
|
||||
* Bepaalt of de huidige verbinding HTTPS gebruikt (inclusief reverse proxies / OpenResty / Docker)
|
||||
@@ -472,10 +473,13 @@ function get_logged_in_user(): ?array {
|
||||
|
||||
// 2. Controleer actieve PHP sessie (mits behorend bij vandaag én hetzelfde IP/fingerprint)
|
||||
if (!empty($_SESSION['user_id']) && !empty($_SESSION['is_2fa_verified'])) {
|
||||
// Inactiviteitstimeout (ISO 27001 / SOC 2): 120 minuten (7200s)
|
||||
$maxIdleSeconds = 7200;
|
||||
// Dynamische inactiviteitstimeout conform NIST SP 800-63B / ISO 27001 / OWASP ASVS v4.0
|
||||
$maxIdleSeconds = function_exists('get_session_idle_timeout') ? get_session_idle_timeout() : 1800;
|
||||
if (!empty($_SESSION['last_activity']) && ($now - (int)$_SESSION['last_activity']) > $maxIdleSeconds) {
|
||||
fociz_log_audit((int)$_SESSION['user_id'], 'SESSION_IDLE_TIMEOUT', 'users', (int)$_SESSION['user_id'], ['idle_seconds' => $now - (int)$_SESSION['last_activity']], 'WARNING');
|
||||
fociz_log_audit((int)$_SESSION['user_id'], 'SESSION_IDLE_TIMEOUT', 'users', (int)$_SESSION['user_id'], ['idle_seconds' => $now - (int)$_SESSION['last_activity'], 'max_idle' => $maxIdleSeconds], 'WARNING');
|
||||
// Invalideer dagsessie token in database zodat herstel via cookie uitgesloten is
|
||||
$stmtClear = $db->prepare("UPDATE users SET remember_token = NULL, remember_token_expires_at = NULL WHERE id = ?");
|
||||
$stmtClear->execute([$_SESSION['user_id']]);
|
||||
$_SESSION = ['session_was_expired' => true, 'idle_timeout' => true];
|
||||
clear_day_session_cookie();
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
@@ -484,6 +488,20 @@ function get_logged_in_user(): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Absolute sessielimiet (NIST SP 800-63B): max 10 uur aaneengesloten sessie per dag
|
||||
$maxSessionDuration = 36000;
|
||||
if (!empty($_SESSION['login_time']) && ($now - (int)$_SESSION['login_time']) > $maxSessionDuration) {
|
||||
fociz_log_audit((int)$_SESSION['user_id'], 'SESSION_ABSOLUTE_TIMEOUT', 'users', (int)$_SESSION['user_id'], ['duration' => $now - (int)$_SESSION['login_time']], 'WARNING');
|
||||
$stmtClear = $db->prepare("UPDATE users SET remember_token = NULL, remember_token_expires_at = NULL WHERE id = ?");
|
||||
$stmtClear->execute([$_SESSION['user_id']]);
|
||||
$_SESSION = ['session_was_expired' => true, 'absolute_timeout' => true];
|
||||
clear_day_session_cookie();
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
@session_regenerate_id(true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// IP-verificatie: als het IP/locatie tussentijds verandert, moet er opnieuw worden ingelogd
|
||||
if (!empty($_SESSION['auth_fingerprint']) && $_SESSION['auth_fingerprint'] !== $clientFingerprint) {
|
||||
$_SESSION = ['session_was_expired' => true, 'ip_changed' => true];
|
||||
@@ -498,6 +516,20 @@ function get_logged_in_user(): ?array {
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$user = $stmt->fetch();
|
||||
if ($user) {
|
||||
// Periodieke sessie-ID rotatie (OWASP ASVS v4.0 §3.3): elke 30 minuten ter voorkoming van session hijacking
|
||||
if (empty($_SESSION['last_rotated'])) {
|
||||
$_SESSION['last_rotated'] = $now;
|
||||
} elseif (($now - (int)$_SESSION['last_rotated']) > 1800) {
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
@session_regenerate_id(true);
|
||||
}
|
||||
$_SESSION['last_rotated'] = $now;
|
||||
}
|
||||
|
||||
if (empty($_SESSION['login_time'])) {
|
||||
$_SESSION['login_time'] = $now;
|
||||
}
|
||||
|
||||
$_SESSION['auth_date'] = $today;
|
||||
$_SESSION['auth_fingerprint'] = $clientFingerprint;
|
||||
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
|
||||
@@ -510,7 +542,7 @@ function get_logged_in_user(): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3. Fallback dagsessie-token: herstelt sessie na browserherstart of server idle timeout (uitsluitend vandaag!)
|
||||
// 3. Fallback dagsessie-token: herstelt sessie na browserherstart (uitsluitend vandaag!)
|
||||
$dayToken = $_COOKIE['fociz_day_session'] ?? ($_COOKIE['fociz_remember'] ?? null);
|
||||
if (!empty($dayToken) && is_string($dayToken)) {
|
||||
$stmt = $db->prepare("SELECT id, name, email, role, two_factor_enabled, avatar_url, theme, notification_settings, default_jira_filter_code, fociz_widget_layout, created_at FROM users WHERE remember_token = ? AND remember_token_expires_at >= NOW() AND DATE(remember_token_expires_at) = ?");
|
||||
@@ -534,6 +566,8 @@ function get_logged_in_user(): ?array {
|
||||
$_SESSION['auth_fingerprint'] = $clientFingerprint;
|
||||
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
|
||||
$_SESSION['last_activity'] = $now;
|
||||
$_SESSION['login_time'] = $now;
|
||||
$_SESSION['last_rotated'] = $now;
|
||||
return $user;
|
||||
}
|
||||
// Token is ongeldig of van gisteren
|
||||
|
||||
Reference in New Issue
Block a user