Implement session expiration enforcement: clear remember cookies and redirect to login on session expiry; update header script for daily re-login requirement.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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');
|
||||
|
||||
+2
-2
@@ -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']);
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+38
-66
@@ -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);
|
||||
|
||||
clear_remember_cookie();
|
||||
try {
|
||||
$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;
|
||||
$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);
|
||||
$isExpired = true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 1. Controleer actieve PHP sessie
|
||||
if (!empty($_SESSION['user_id']) && !empty($_SESSION['is_2fa_verified'])) {
|
||||
$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;
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -57,10 +57,20 @@ $currentUserTheme = !empty($currentUser['id']) ? get_user_theme((int)$currentUse
|
||||
</script>
|
||||
<!-- Lucide Icons -->
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
<!-- Dagsessie Expiratie Watchdog: reset iedere nacht om 23:59:59 -->
|
||||
<!-- Dagsessie Expiratie Watchdog: reset iedere nacht om 23:59:59 en dwingt dagelijks opnieuw inloggen af -->
|
||||
<script>
|
||||
(function() {
|
||||
try {
|
||||
const sessionDate = "<?= date('Y-m-d') ?>";
|
||||
const checkMidnight = function() {
|
||||
const now = new Date();
|
||||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
|
||||
const todayStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0');
|
||||
if (todayStr !== sessionDate || now.getTime() > midnight.getTime()) {
|
||||
window.location.href = '/auth/login.php?expired=1';
|
||||
}
|
||||
};
|
||||
|
||||
const now = new Date();
|
||||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
|
||||
const msUntilMidnight = midnight.getTime() - now.getTime();
|
||||
@@ -69,6 +79,15 @@ $currentUserTheme = !empty($currentUser['id']) ? get_user_theme((int)$currentUse
|
||||
window.location.href = '/auth/login.php?expired=1';
|
||||
}, msUntilMidnight);
|
||||
}
|
||||
|
||||
// Controleer direct zodra de gebruiker de browser weer activeert (bij bijv. standby / slaapstand overnacht)
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (document.visibilityState === 'visible') {
|
||||
checkMidnight();
|
||||
}
|
||||
});
|
||||
window.addEventListener('focus', checkMidnight);
|
||||
setInterval(checkMidnight, 30000);
|
||||
} catch(e) {}
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user