prepare("SELECT id, name, email, password_hash, two_factor_secret, two_factor_enabled FROM users WHERE email = ?"); $stmt->execute([$email]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password_hash'])) { fociz_clear_rate_limit($emailRateKey); // Controleer of de inloglocatie/IP bekend is $isIpKnown = fociz_is_ip_known_for_user((int)$user['id'], $clientIp); if (!$isIpKnown) { // Stuur verificatie-mail en informeer gebruiker fociz_send_new_ip_verification((int)$user['id'], $user['email'], $user['name'], $clientIp); fociz_log_audit((int)$user['id'], 'LOGIN_NEW_IP_CHALLENGE', 'user', (int)$user['id'], ['ip' => $clientIp], 'PENDING', $user['email']); $error = "Nieuwe inloglocatie gedetecteerd ({$clientIp}). Er is een verificatie-e-mail gestuurd naar {$user['email']}. Klik op de link in de e-mail om deze locatie toe te staan."; } else { // Succesvol stap 1: zet tijdelijke pending sessie voor 2FA $_SESSION['pending_2fa_user_id'] = $user['id']; $_SESSION['pending_2fa_user_email'] = $user['email']; $_SESSION['pending_2fa_user_name'] = $user['name']; $step = 2; } } else { fociz_hit_rate_limit($ipRateKey, 900); if (!empty($email)) { fociz_hit_rate_limit($emailRateKey, 900); } fociz_log_audit($user ? (int)$user['id'] : null, 'LOGIN_FAILED', 'user', $user ? (int)$user['id'] : null, ['reason' => 'Invalid credentials', 'ip' => $clientIp], 'FAILURE', $email); $error = "Onjuist e-mailadres of wachtwoord."; } } } // STAP 2: 2FA TOTP Code verificatie elseif ($step === 2) { $userId = $_SESSION['pending_2fa_user_id'] ?? null; $totpCode = trim($_POST['totp_code'] ?? ''); if (!$userId) { header('Location: /auth/login.php'); exit; } $totpRateKey = "login_totp_{$userId}"; $totpLimit = fociz_check_rate_limit($totpRateKey, 5, 900); if (!$totpLimit['allowed']) { $error = "Te veel ongeldige verificatiecodes. Probeer het over " . ceil($totpLimit['retry_after'] / 60) . " minuten opnieuw."; } elseif (empty($totpCode)) { $error = "Vul de 6-cijferige 2FA code in uit uw authenticator app."; } else { $stmt = $db->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$userId]); $user = $stmt->fetch(); $isValid = false; // Controleer reguliere TOTP code if (!empty($user['two_factor_secret'])) { try { $isValid = TOTP::verifyCode($user['two_factor_secret'], $totpCode); } catch (Throwable $t) { error_log("TOTP verificatiefout: " . $t->getMessage()); $isValid = false; } } // Fallback: controleer 8-karakter backup codes if (!$isValid && !empty($user['backup_codes'])) { $backupCodes = json_decode($user['backup_codes'], true) ?: []; $codeUpper = strtoupper($totpCode); $key = array_search($codeUpper, $backupCodes); if ($key !== false) { $isValid = true; // Verbruik de backup code unset($backupCodes[$key]); $stmtUpdate = $db->prepare("UPDATE users SET backup_codes = ? WHERE id = ?"); $stmtUpdate->execute([json_encode(array_values($backupCodes)), $userId]); } } if ($isValid) { fociz_clear_rate_limit($totpRateKey); fociz_clear_rate_limit($ipRateKey); // Volledige login succesvol (geldig tot 23:59:59 van vandaag) fociz_register_user_ip((int)$user['id'], $clientIp, true); // Session Fixation Beveiliging (OWASP ASVS v4.0 §3.3.1 / SOC 2 CC6.6): // Genereer direct een nieuw cryptografisch sessie-ID en vernietig de pre-auth sessie if (session_status() === PHP_SESSION_ACTIVE) { session_regenerate_id(true); } $newSessionId = session_id(); $_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'] = date('Y-m-d'); $_SESSION['auth_fingerprint'] = fociz_get_client_fingerprint(); $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); $_SESSION['last_activity'] = time(); $_SESSION['login_time'] = time(); $_SESSION['last_rotated'] = time(); // Dagsessie-token uitgeven (strikt geldig tot 23:59:59 van vandaag) issue_day_session_token((int)$user['id']); // Registreer actieve sessie in user_sessions (SOC 2 / ISO 27001) $maxIdleSeconds = function_exists('get_session_idle_timeout') ? get_session_idle_timeout() : 1800; fociz_register_active_session((int)$user['id'], $newSessionId, $maxIdleSeconds); fociz_log_audit((int)$user['id'], 'LOGIN_SUCCESS', 'user', (int)$user['id'], ['ip' => $clientIp, 'auth_method' => 'PASSWORD+2FA'], 'SUCCESS', $user['email']); unset($_SESSION['pending_2fa_user_id'], $_SESSION['pending_2fa_user_email'], $_SESSION['pending_2fa_user_name']); header('Location: /planner.php'); exit; } else { fociz_hit_rate_limit($totpRateKey, 900); fociz_hit_rate_limit($ipRateKey, 900); fociz_log_audit((int)$userId, 'LOGIN_MFA_FAILED', 'user', (int)$userId, ['ip' => $clientIp], 'FAILURE', $_SESSION['pending_2fa_user_email'] ?? null); $error = "Onjuiste 2FA code. Controleer uw authenticator app en probeer opnieuw."; } } } } $pageTitle = "Fociz — Inloggen"; ?> <?= htmlspecialchars($pageTitle) ?>

Fociz

Veilig inloggen met tweestapsverificatie (2FA)

Voer uw 6-cijferige verificatiecode in

Gekoppeld aan

Terug
Toegang tot Fociz is strikt op uitnodiging. Vraag uw beheerder om een uitnodigingslink.