SESSION_TIMEOUT) { self::destroy(); session_start(); } } $_SESSION['_last_activity'] = time(); } /** * 校验密码 */ public static function verifyPassword(string $password): bool { // 登录失败延迟(防止暴力破解) usleep(LOGIN_DELAY * 1000); return password_verify($password, SITE_PASSWORD_HASH); } /** * 执行登录 */ public static function login(): void { self::initSession(); $_SESSION['logged_in'] = true; $_SESSION['_login_time'] = time(); session_regenerate_id(true); } /** * 执行登出 */ public static function logout(): void { self::initSession(); self::destroy(); } /** * 检查是否已登录 */ public static function isLoggedIn(): bool { self::initSession(); return !empty($_SESSION['logged_in']) && $_SESSION['logged_in'] === true; } /** * 要求登录,未登录则返回 401 */ public static function requireLogin(): void { if (!self::isLoggedIn()) { Response::error('请先登录', 401); } } /** * 生成 CSRF Token 并存入 Session */ public static function generateCsrfToken(): string { self::initSession(); $token = bin2hex(random_bytes(32)); $_SESSION['csrf_token'] = $token; return $token; } /** * 验证 CSRF Token */ public static function validateCsrfToken(?string $token): bool { self::initSession(); if (empty($_SESSION['csrf_token']) || empty($token)) { return false; } return hash_equals($_SESSION['csrf_token'], $token); } /** * 获取 CSRF Token(用于前端表单) */ public static function getCsrfToken(): string { self::initSession(); if (empty($_SESSION['csrf_token'])) { return self::generateCsrfToken(); } return $_SESSION['csrf_token']; } /** * 生成 CSRF 隐藏字段 HTML */ public static function csrfField(): string { return ''; } /** * 添加安全响应头 */ public static function sendSecurityHeaders(): void { header('X-Frame-Options: DENY'); header('X-Content-Type-Options: nosniff'); header('X-XSS-Protection: 1; mode=block'); header('Referrer-Policy: strict-origin-when-cross-origin'); } /** * 销毁会话 */ private static function destroy(): void { $_SESSION = []; if (ini_get('session.use_cookies')) { $params = session_get_cookie_params(); setcookie( session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly'] ); } session_destroy(); } }