diff --git a/assets/js/notifications.js b/assets/js/notifications.js index cb472a4..884c8ac 100644 --- a/assets/js/notifications.js +++ b/assets/js/notifications.js @@ -254,6 +254,10 @@ isFetchingEvents = true; try { const res = await fetch('/api/notifications.php?action=get_events', { cache: 'no-store' }); + if (res.status === 401) { + window.location.href = '/auth/login.php?expired=1'; + return; + } if (res.ok) { const data = await res.json(); if (data && data.success) { diff --git a/auth/callback_microsoft.php b/auth/callback_microsoft.php index a045b3a..d397439 100644 --- a/auth/callback_microsoft.php +++ b/auth/callback_microsoft.php @@ -29,7 +29,7 @@ if (empty($_SESSION['user_id']) && $stateUserId) { $_SESSION['is_2fa_verified'] = true; $_SESSION['auth_date'] = date('Y-m-d'); $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); - issue_remember_token((int)$recoveredUser['id']); + clear_remember_cookie(); } } catch (Throwable $e) { // Foutafhandeling diff --git a/auth/invite.php b/auth/invite.php index 915d2f1..d5590d7 100644 --- a/auth/invite.php +++ b/auth/invite.php @@ -83,7 +83,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $_SESSION['is_2fa_verified'] = true; $_SESSION['auth_date'] = date('Y-m-d'); $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); - issue_remember_token($newUserId); + clear_remember_cookie(); unset($_SESSION['invite_totp_secret']); header('Location: /planner.php'); diff --git a/auth/login.php b/auth/login.php index 37d9054..deae950 100644 --- a/auth/login.php +++ b/auth/login.php @@ -108,8 +108,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $_SESSION['auth_date'] = date('Y-m-d'); $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); - // Activeer dagspecifieke remember token (verloopt vannacht om 23:59:59) - issue_remember_token((int)$user['id']); + // Zorg dat er geen persistente remember cookies worden gebruikt + clear_remember_cookie(); unset($_SESSION['pending_2fa_user_id'], $_SESSION['pending_2fa_user_email'], $_SESSION['pending_2fa_user_name']); diff --git a/auth/setup.php b/auth/setup.php index ffe70d8..3e008e1 100644 --- a/auth/setup.php +++ b/auth/setup.php @@ -70,7 +70,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $_SESSION['is_2fa_verified'] = true; $_SESSION['auth_date'] = date('Y-m-d'); $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); - issue_remember_token($adminId); + clear_remember_cookie(); unset($_SESSION['setup_totp_secret']); $success = true; diff --git a/includes/auth.php b/includes/auth.php index f0b7364..0e65793 100644 --- a/includes/auth.php +++ b/includes/auth.php @@ -76,6 +76,9 @@ function ensure_remember_token_columns(PDO $db): void { $result = $db->query("SHOW COLUMNS FROM `users` LIKE 'remember_token'"); if (!$result || $result->rowCount() === 0) { $db->exec("ALTER TABLE `users` ADD COLUMN `remember_token` VARCHAR(64) NULL AFTER `backup_codes`, ADD COLUMN `remember_token_expires_at` DATETIME NULL AFTER `remember_token`"); + } else { + // Maak alle bestaande actieve tokens direct leeg zodat geen enkele oude persistente browser-sessie blijft bestaan + $db->exec("UPDATE `users` SET `remember_token` = NULL, `remember_token_expires_at` = NULL WHERE `remember_token` IS NOT NULL"); } } catch (Throwable $e) { // Stil negeren indien al aanwezig of tijdens migraties @@ -119,35 +122,23 @@ function ensure_theme_column(PDO $db): void { } /** - * Genereert en bewaart een dagspecifieke login token in MariaDB en plaatst een veilige cookie. - * Verloopt altijd dezelfde nacht om 23:59:59 zodat sessies niet meerdere dagen blijven staan. + * Verouderde functie voor persistent login. + * Bewust geneutraliseerd: cookies worden direct gewist en geen tokens meer aangemaakt, + * zodat gebruikers iedere dag om 23:59:59 worden uitgelogd en daadwerkelijk opnieuw moeten inloggen. */ function issue_remember_token(int $userId): string { - $rawToken = bin2hex(random_bytes(32)); - $tokenHash = hash('sha256', $rawToken); - $midnightTs = strtotime('today 23:59:59'); - $expiresAt = date('Y-m-d 23:59:59', $midnightTs); - - $db = get_db_connection(); - ensure_remember_token_columns($db); - - $stmt = $db->prepare("UPDATE users SET remember_token = ?, remember_token_expires_at = ? WHERE id = ?"); - $stmt->execute([$tokenHash, $expiresAt, $userId]); - - $isSecure = is_https_request(); - setcookie('fociz_remember', $rawToken, [ - 'expires' => $midnightTs, // Verloopt vannacht om 23:59:59 - 'path' => '/', - 'secure' => $isSecure, - 'httponly' => true, - 'samesite' => 'Lax' - ]); - - return $rawToken; + clear_remember_cookie(); + try { + $db = get_db_connection(); + ensure_remember_token_columns($db); + $stmt = $db->prepare("UPDATE users SET remember_token = NULL, remember_token_expires_at = NULL WHERE id = ?"); + $stmt->execute([$userId]); + } catch (Throwable $e) {} + return ''; } /** - * Verwijdert de persistente remember cookie + * Verwijdert de persistente remember cookie uit de browser */ function clear_remember_cookie(): void { $isSecure = is_https_request(); @@ -158,11 +149,15 @@ function clear_remember_cookie(): void { 'httponly' => true, 'samesite' => 'Lax' ]); + if (isset($_COOKIE['fociz_remember'])) { + unset($_COOKIE['fociz_remember']); + } } /** * Haalt de huidige ingelogde gebruiker op uit de database. * Garandeert dat de sessie strikt om 23:59:59 gereset wordt en nooit meerdere dagen blijft staan. + * Bevat GEEN persistente cookies of auto-login bypass: de gebruiker moet iedere dag daadwerkelijk opnieuw inloggen. */ function get_logged_in_user(): ?array { start_secure_session(); @@ -170,18 +165,22 @@ function get_logged_in_user(): ?array { $today = date('Y-m-d'); $now = time(); + // Verwijder altijd eventuele oude of achtergebleven fociz_remember cookies + if (isset($_COOKIE['fociz_remember'])) { + clear_remember_cookie(); + } + // Controleer of de sessie van een eerdere dag is of voorbij 23:59:59 + $isExpired = false; if (!empty($_SESSION['auth_date']) && $_SESSION['auth_date'] !== $today) { - $_SESSION = []; - clear_remember_cookie(); - if (session_status() === PHP_SESSION_ACTIVE) { - @session_regenerate_id(true); - } - return null; + $isExpired = true; } - if (!empty($_SESSION['session_expires_at']) && $now > (int)$_SESSION['session_expires_at']) { - $_SESSION = []; + $isExpired = true; + } + + if ($isExpired) { + $_SESSION = ['session_was_expired' => true]; clear_remember_cookie(); if (session_status() === PHP_SESSION_ACTIVE) { @session_regenerate_id(true); @@ -189,11 +188,10 @@ function get_logged_in_user(): ?array { return null; } - $db = get_db_connection(); - ensure_remember_token_columns($db); - - // 1. Controleer actieve PHP sessie + // Controleer actieve PHP sessie (uitsluitend de sessie van vandaag is geldig) if (!empty($_SESSION['user_id']) && !empty($_SESSION['is_2fa_verified'])) { + $db = get_db_connection(); + ensure_remember_token_columns($db); $stmt = $db->prepare("SELECT id, name, email, role, two_factor_enabled, created_at FROM users WHERE id = ?"); $stmt->execute([$_SESSION['user_id']]); $user = $stmt->fetch(); @@ -207,38 +205,6 @@ function get_logged_in_user(): ?array { clear_remember_cookie(); } - // 2. Controleer dagspecifieke cookie (uitsluitend geldig voor vandaag tot 23:59:59) - if (!empty($_COOKIE['fociz_remember'])) { - $rawToken = trim($_COOKIE['fociz_remember']); - $tokenHash = hash('sha256', $rawToken); - - $stmt = $db->prepare(" - SELECT id, name, email, role, two_factor_enabled, created_at - FROM users - WHERE remember_token = ? AND remember_token_expires_at > NOW() - "); - $stmt->execute([$tokenHash]); - $user = $stmt->fetch(); - - if ($user) { - // Herstel PHP sessie voor de huidige werkdag - $_SESSION['user_id'] = $user['id']; - $_SESSION['user_name'] = $user['name']; - $_SESSION['user_email'] = $user['email']; - $_SESSION['user_role'] = $user['role']; - $_SESSION['is_2fa_verified'] = true; - $_SESSION['auth_date'] = $today; - $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); - - // Verleng uitsluitend tot 23:59:59 van vandaag - issue_remember_token((int)$user['id']); - - return $user; - } else { - clear_remember_cookie(); - } - } - return null; } @@ -264,7 +230,7 @@ function require_auth(bool $json = false): array { exit; } - // 2. Controleer of gebruiker ingelogd én 2FA geverifieerd is + // 2. Controleer of gebruiker ingelogd én 2FA geverifieerd is voor vandaag $user = get_logged_in_user(); if (!$user) { if ($isAjax) { @@ -273,7 +239,13 @@ function require_auth(bool $json = false): array { echo json_encode(['success' => false, 'error' => 'Niet geauthenticeerd of sessie verlopen']); exit; } - header('Location: /auth/login.php'); + $wasExpired = !empty($_SESSION['session_was_expired']); + unset($_SESSION['session_was_expired']); + if ($wasExpired) { + header('Location: /auth/login.php?expired=1'); + } else { + header('Location: /auth/login.php'); + } exit; } diff --git a/includes/header.php b/includes/header.php index ccec3a2..f1155e1 100644 --- a/includes/header.php +++ b/includes/header.php @@ -57,10 +57,20 @@ $currentUserTheme = !empty($currentUser['id']) ? get_user_theme((int)$currentUse - +