| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- <?php
- namespace BCJD;
- /**
- * Auth - 认证管理(登录/CSRF/Session 安全)
- *
- * 安全特性:
- * - CSRF Token 自动生成与验证
- * - Session 固定会话防护(regenerate_id)
- * - Session 超时机制(30分钟无操作自动过期)
- * - 登录失败延迟(防暴力破解)
- * - 安全的 Cookie 参数
- * - bcrypt 密码哈希验证
- */
- class Auth
- {
- /**
- * 初始化 Session 安全配置
- */
- public static function initSession(): void
- {
- if (session_status() === PHP_SESSION_ACTIVE) {
- return;
- }
- // 仅通过 Cookie 传递 Session ID
- ini_set('session.use_only_cookies', '1');
- ini_set('session.use_strict_mode', '1');
- ini_set('session.cookie_httponly', '1');
- ini_set('session.cookie_samesite', 'Lax');
- ini_set('session.cookie_secure', '0'); // 如果使用 HTTPS 可改为 1
- ini_set('session.gc_maxlifetime', (string)SESSION_TIMEOUT);
- session_start();
- // Session 超时检查
- if (!empty($_SESSION['_last_activity'])) {
- if (time() - $_SESSION['_last_activity'] > 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 '<input type="hidden" name="csrf_token" value="' . self::getCsrfToken() . '">';
- }
- /**
- * 添加安全响应头
- */
- 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();
- }
- }
|