SESSION_LIFETIME, 'path' => '/', 'secure' => $secure, 'httponly' => true, 'samesite' => 'Strict', ]); session_start(); // Session-ID alle 15 Minuten erneuern if (!isset($_SESSION['_last_regeneration'])) { $_SESSION['_last_regeneration'] = time(); } elseif (time() - $_SESSION['_last_regeneration'] > 900) { session_regenerate_id(true); $_SESSION['_last_regeneration'] = time(); } } function auth_is_logged_in(): bool { return !empty($_SESSION['user_id']); } function auth_require_login(): void { if (!auth_is_logged_in()) { redirect('/admin/login.php'); } } function auth_login(string $username, string $password): bool { $stmt = db()->prepare('SELECT id, password_hash, display_name FROM users WHERE username = ?'); $stmt->execute([$username]); $user = $stmt->fetch(); if (!$user || !password_verify($password, $user['password_hash'])) { auth_record_attempt(); return false; } // Session erneuern bei Login session_regenerate_id(true); $_SESSION['user_id'] = $user['id']; $_SESSION['display_name'] = $user['display_name']; $_SESSION['_last_regeneration'] = time(); // Fehlversuche löschen $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $stmt = db()->prepare('DELETE FROM login_attempts WHERE ip_address = ?'); $stmt->execute([$ip]); return true; } function auth_logout(): void { $_SESSION = []; if (ini_get('session.use_cookies')) { $p = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'], $p['httponly']); } session_destroy(); } function csrf_token(): string { if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token']; } function csrf_field(): string { return ''; } function csrf_verify(): void { $token = $_POST['csrf_token'] ?? ''; if (!hash_equals(csrf_token(), $token)) { http_response_code(403); die('Ungültiges CSRF-Token.'); } } function auth_check_rate_limit(): bool { $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $stmt = db()->prepare( 'SELECT COUNT(*) FROM login_attempts WHERE ip_address = ? AND attempted_at > datetime("now", ?)' ); $stmt->execute([$ip, '-' . LOGIN_LOCKOUT_MINUTES . ' minutes']); $count = (int) $stmt->fetchColumn(); return $count < LOGIN_MAX_ATTEMPTS; } function auth_record_attempt(): void { $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $stmt = db()->prepare('INSERT INTO login_attempts (ip_address) VALUES (?)'); $stmt->execute([$ip]); } function auth_user_id(): ?int { return $_SESSION['user_id'] ?? null; } function auth_display_name(): string { return $_SESSION['display_name'] ?? 'Admin'; }