bin2hex(random_bytes(32)), 'created_at' => time(), ]; } return $_SESSION['csrf_token']['value']; } /** * Vérifie si le token a expiré */ private static function isExpired(): bool { $createdAt = $_SESSION['csrf_token']['created_at'] ?? 0; return (time() - $createdAt) > self::EXPIRATION; } /** * Valide le token soumis */ public static function validateToken(string $submittedToken): bool { // Rejeté si la session ne contient pas de token if (empty($_SESSION['csrf_token'])) return false; // Rejeté si expiré if (self::isExpired()) { self::regenerate(); return false; } // Comparaison sécurisée (résistante aux attaques par timing) return hash_equals($_SESSION['csrf_token']['value'], $submittedToken); } /** * Champ HTML à insérer dans les formulaires */ public static function field(): string { $token = self::generateToken(); return ''; } /** * Régénère le token (déconnexion, ou expiration) */ public static function regenerate(): void { $_SESSION['csrf_token'] = [ 'value' => bin2hex(random_bytes(32)), 'created_at' => time(), ]; } }