Поведенческая биометрия под микроскопом: как обучить свой AI эмулятор человека

Good Carder

Professional
Messages
753
Reaction score
493
Points
63

Введение: почему статические методы больше не работают​

Вы можете иметь идеальный антидетект, свежие резидентные прокси и карту с подходящим BIN. Но платёж всё равно падает с ошибкой fraudulent. Почему? Потому что сайт анализирует не только то, кто вы, но и как вы двигаетесь.

Технологии поведенческой биометрии — новый рубеж в обнаружении автоматизации. BioCatch анализирует более 2000 параметров, включая скорость ввода, паттерны касаний и плавность движений мыши. BehavioSec отслеживает ритм нажатия клавиш и движения мыши в реальном времени. NuData Security с 99% точностью распознаёт неавторизованных пользователей даже при правильных учётных данных.

В этой статье я разберу:
  • Какие именно параметры собирают BioCatch, BehavioSec и NuData.
  • Как собрать датасет реальных пользовательских сессий через rrweb.
  • Библиотеки для эмуляции человеческих движений (ghost-cursor, humanize).
  • Использование LSTM для генерации траекторий, неотличимых от человеческих.
  • Метрики оценки качества эмуляции.

Часть 1. Что собирают системы поведенческой биометрии​

BioCatch отслеживает более 2 000 поведенческих параметров, анализируя всё — от координации глаз и рук до малейших колебаний мыши.

BehavioSec анализирует характерные интервалы между нажатиями конкретных клавиш, скорость ввода и передвижение курсора в определённых ситуациях.

1.1. Топ-10 параметров мыши, которые вас выдают​

ПараметрЧто измеряетКак бот обычно ошибается
Скорость движенияПикселей в секундуПостоянная скорость без ускорения/замедления
Ускорение/замедлениеВторая производная позицииЛинейная функция без плавных переходов
Дрожание курсораМикроколебания траекторииАбсолютно прямая линия
Точность попаданияРасстояние до центра целиИдеальное попадание в центр
Время реакцииПауза перед началом движенияОтсутствие пауз («мгновенная реакция»)
Углы поворотаРаспределение направлений движенияПредсказуемые углы (45°, 90°)
Пропуск цели (overshoot)Проскальзывание мимо целиРедкое явление у ботов
МикрокоррекцииМелкие движения после остановкиОтсутствуют
Сглаживание путиКак сглажена траекторияИдеальные кривые Безье
Hover-паузыВремя наведения перед кликомМгновенный клик без наведения

1.2. Параметры клавиатуры​

ПараметрЧто измеряетПример ботового отклонения
Dwell timeВремя удержания клавишиПостоянное время для всех клавиш
Flight timeВремя между отпусканием и следующим нажатиемРавные интервалы между символами
Ритм вводаПаттерн задержекОтсутствие естественной вариативности
Использование TabНавигация между полямиПоследовательный обход всех полей без пропусков
Ошибки и исправленияЧастота BackspaceОтсутствуют — идеальный ввод с первой попытки

Современные системы обработки не ограничиваются анализом клавиатуры и мыши на десктопе. На мобильных устройствах они собирают дополнительную информацию, включая данные гироскопа и акселерометра, а также отслеживают характер свайпов.

Часть 2. Сбор датасета реальных сессий через rrweb​

Чтобы эмулировать человека, вы должны сначала понять, как он двигается. Лучший способ — записать реальные сессии и проанализировать их.

2.1. Что такое rrweb​

RRWeb (Record and Replay the Web) — библиотека с открытым исходным кодом для записи и воспроизведения веб-сессий. Она записывает не скриншоты, а DOM-события: изменения DOM, движения мыши, клики, ввод с клавиатуры — всё с временными метками.

2.2. Установка и базовая конфигурация​

HTML:
<!-- Подключение rrweb -->
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"></script>

<script>
    let events = [];
    let recordingInterval = null;
    
    // Конфигурация записи с полным набором событий
    const recordingConfig = {
        emit(event) {
            events.push(event);
        },
        // Запись всех движений мыши (каждый пиксель)
        recordMouseMove: true,
        // Запись скролла
        recordScroll: true,
        // Запись ввода с клавиатуры
        recordInput: true,
        // Запись кликов
        recordClick: true,
        // Частота сэмплирования движений мыши (в миллисекундах)
        sampling: {
            mousemove: 10  // собираем данные каждые 10 мс -> 100 точек/секунду
        }
    };
    
    // Начало записи
    const stopRecording = rrweb.record(recordingConfig);
    
    // Остановка через 5 минут (или по событию)
    setTimeout(() => {
        stopRecording();
        // Сохраняем events в localStorage или отправляем на сервер
        console.log(`Собрано ${events.length} событий`);
        localStorage.setItem('session', JSON.stringify(events));
    }, 300000);
    
    // Экспорт в CSV для анализа в Python
    function exportToCSV() {
        const events = JSON.parse(localStorage.getItem('session'));
        const mouseEvents = events.filter(e => e.type === 3); // тип 3 = MouseMove
        
        let csv = 'timestamp,x,y,target\n';
        for (const ev of mouseEvents) {
            csv += `${ev.timestamp},${ev.data.x},${ev.data.y},${ev.data.target}\n`;
        }
        
        // Скачивание CSV
        const blob = new Blob([csv], {type: 'text/csv'});
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'mouse_movements.csv';
        a.click();
    }
</script>

2.3. Расширенная настройка: запись кастомных событий​

RRWeb поддерживает запись кастомных событий через API, позволяя синхронизировать данные с другими источниками или добавлять метаинформацию.
JavaScript:
// Запись кастомного события
rrweb.record({
    emit(event) { events.push(event); },
    recordMouseMove: true,
    sampling: { mousemove: 10 },
    // Кастомный обработчик для дополнительных данных
    hooks: {
        beforeEmit(event) {
            if (event.type === 3) {  // MouseMove
                event.data.screenSize = {
                    width: window.innerWidth,
                    height: window.innerHeight
                };
            }
            return event;
        }
    }
});

2.4. Воспроизведение записанной сессии​

JavaScript:
// Воспроизведение сессии с использованием rrweb-player
const events = JSON.parse(localStorage.getItem('session'));
new rrwebPlayer({
    target: document.getElementById('replay-container'),
    props: {
        events,
        width: 1024,
        height: 768,
        autoPlay: true,
        showController: true
    }
});

2.5. Сбор датасета: методика​

Для создания обучающего датасета необходимо:
  1. Собрать сессии минимум 50 разных пользователей (каждая сессия 3-5 минут).
  2. Разнообразные задачи: заполнение форм, навигация по сайту, скроллинг.
  3. Разные устройства: десктопы с мышью и трекпадом, мобильные устройства.
  4. Ручная разметка: пометка участков с «естественным» и «неестественным» поведением (отвлекался, замедлялся и т.д.).

Часть 3. Библиотеки имитации движений​

3.1. Ghost Cursor — золотой стандарт для Puppeteer​

Ghost Cursor — утилита для Puppeteer, генерирующая реалистичные, похожие на человеческие движения мыши между координатами. Вместо мгновенного прыжка (page.mouse.click(x, y)) Ghost Cursor передвигает курсор по кривым Безье.
JavaScript:
const puppeteer = require('puppeteer');
const ghostCursor = require('ghost-cursor');

const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com');

const cursor = ghostCursor.createCursor(page);
await cursor.moveTo('#submit-button');     // Движение как у человека
await cursor.click();                      // Клик со случайным смещением

Ключевые особенности Ghost Cursor 2025-2026:
  • Автоматический выбор случайных координат внутри элемента (вместо идеального центра).
  • Генерация набора точек для движения между двумя координатами.
  • Позволяет создавать собственные последовательности движений.
  • Явно не является «серебряной пулей» для сложных систем защиты, но значительно снижает автоматизационные сигналы.

3.2. @extra/humanize — плагин для Playwright и Puppeteer​

@extra/humanize — это плагин, эмулирующий человеческий ввод, с особым акцентом на движения мыши.
JavaScript:
const playwright = require('playwright');
const humanize = require('@extra/humanize');

const browser = await playwright.chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();

// Человеко-подобный клик с под-пиксельной точностью и реалистичным движением
await humanize.click(page, '#button', {
    waitTime: 500,        // пауза перед движением (человек «прицеливается»)
    moveSpeed: 0.8,       // относительная скорость движения (0-1)
    variation: 5          // пикселей случайного смещения от целевой точки
});

3.3. Библиотеки для Python (автономное использование)​

БиблиотекаАлгоритмОсобенность
human_mouseКривые Безье + сплайн-интерполяцияУльтра-реалистичные траектории на основе сложных математических алгоритмов
WindMouseАлгоритм WindMouseСоздаёт нелинейные траектории с переменной скоростью, естественные шумы
BumblebeeRNN + LSTMAI-движок, предсказывающий естественные траектории с помощью глубокого обучения

Пример использования human_mouse:
Python:
from human_mouse import HumanMouse
import pyautogui

human = HumanMouse()
# Перемещение мыши из текущей позиции в (500, 500) за 0.8 секунды
human.move_to(500, 500, duration=0.8, bezier=True)
# Клик с человеческим патерном (hover + вариация)
human.click(500, 500, hover_duration=0.2, variation=5)

3.4. Ghost Cursor на Python (автономная версия)​

Существуют реализации алгоритма Ghost Cursor для использования без Puppeteer:
Python:
class HumanMouse:
    def __init__(self):
        self.current_pos = pyautogui.position()
        self.bezier_points = []
    
    def generate_bezier_curve(self, end_x, end_y, steps=50):
        """Генерация кривой Безье между точками"""
        cp1_x = self.current_pos[0] + (end_x - self.current_pos[0]) * 0.25 + random.randint(-30, 30)
        cp1_y = self.current_pos[1] + (end_y - self.current_pos[1]) * 0.25 + random.randint(-30, 30)
        cp2_x = self.current_pos[0] + (end_x - self.current_pos[0]) * 0.75 + random.randint(-30, 30)
        cp2_y = self.current_pos[1] + (end_y - self.current_pos[1]) * 0.75 + random.randint(-30, 30)
        
        points = []
        for i in range(steps + 1):
            t = i / steps
            x = (1-t)**3 * self.current_pos[0] + 3*(1-t)**2*t * cp1_x + 3*(1-t)*t**2 * cp2_x + t**3 * end_x
            y = (1-t)**3 * self.current_pos[1] + 3*(1-t)**2*t * cp1_y + 3*(1-t)*t**2 * cp2_y + t**3 * end_y
            points.append((x, y))
        return points
    
    def move_to(self, x, y, duration=0.5):
        points = self.generate_bezier_curve(x, y, steps=int(duration * 60))
        for point in points:
            pyautogui.moveTo(point[0], point[1], duration=0.01)
            time.sleep(0.01 + random.uniform(0, 0.01))
        self.current_pos = (x, y)

Часть 4. Использование LSTM для генерации естественных траекторий​

4.1. Архитектура нейронной сети для генерации движений мыши​

Современный подход к эмуляции человека — использование рекуррентных нейронных сетей для предсказания естественных движений.

Bumblebee — пример AI-пакета, использующего RNN с LSTM-слоём для генерации естественных траекторий мыши:
Code:
RNN + LSTM Layer
    ↓
Генерация базовой траектории
    ↓
Добавление естественного шума и вариативной скорости
    ↓
Итоговое движение, близкое к реальному человеческому

4.2. Сбор обучающих данных​

Обучающий датасет должен содержать размеченные траектории мыши из реальных сессий. Доступные наборы данных включают SapiMouse dataset и наборы с платформ вроде CleverSys.

Процесс подготовки данных:
  1. Запись сессий через rrweb (как описано в Части 2).
  2. Экспорт координат в CSV с временными метками.
  3. Нормализация координат относительно размера экрана.
  4. Создание последовательностей для LSTM (вход: предыдущие N точек, выход: следующая точка).

Пример структуры данных:
Python:
import numpy as np
from sklearn.preprocessing import MinMaxScaler

def prepare_lstm_data(mouse_trajectories, seq_length=10):
    """
    mouse_trajectories: список массивов (n_points, 2)
    seq_length: сколько предыдущих точек используем для предсказания следующей
    """
    X, y = [], []
    for trajectory in mouse_trajectories:
        # Нормализация координат
        scaler = MinMaxScaler()
        trajectory_norm = scaler.fit_transform(trajectory)
        
        for i in range(len(trajectory_norm) - seq_length):
            X.append(trajectory_norm[i:i+seq_length])
            y.append(trajectory_norm[i+seq_length])
    
    return np.array(X), np.array(y)

4.3. Обучение LSTM в PyTorch​

Python:
import torch
import torch.nn as nn

class MouseMovementLSTM(nn.Module):
    def __init__(self, input_size=2, hidden_size=64, num_layers=2, output_size=2):
        super(MouseMovementLSTM, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
        
        out, _ = self.lstm(x, (h0, c0))
        out = self.fc(out[:, -1, :])
        return out

# Пример обучения
model = MouseMovementLSTM(input_size=2, hidden_size=64, num_layers=2, output_size=2)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(100):
    outputs = model(X_tensor)
    loss = criterion(outputs, y_tensor)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

4.4. Генерация траектории с использованием обученной модели​

Python:
def generate_trajectory(model, start_pos, target_pos, steps=100, temperature=0.1):
    """
    Генерация траектории мыши с использованием обученной LSTM
    temperature: контролирует случайность (0=детерминированный, 1=случайный)
    """
    trajectory = [start_pos]
    current = torch.tensor(start_pos).float().unsqueeze(0).unsqueeze(0)
    
    for _ in range(steps):
        with torch.no_grad():
            next_pos = model(current).squeeze().numpy()
        
        # Добавление управляемой случайности
        noise = np.random.normal(0, temperature, size=2)
        next_pos = next_pos + noise
        
        # Корректировка направления к цели (серийное планирование)
        direction_to_target = (np.array(target_pos) - next_pos) / (steps - len(trajectory))
        next_pos = next_pos + direction_to_target * 0.1
        
        trajectory.append(next_pos)
        current = torch.tensor(next_pos).float().unsqueeze(0).unsqueeze(0)
    
    return trajectory

Часть 5. Создание скрипта, неотличимого от человека​

5.1. Комбинированный подход​

Самый эффективный способ создать неотличимый скрипт — комбинация нескольких методов:
КомпонентИнструментФункция
Движение мышиLSTM-модель + ghost-cursorЕстественные траектории с вариативной скоростью
Ввод с клавиатурыКастомный type с вариативными задержкамиРеалистичный ритм набора
СкроллСлучайные паузы и возвраты вверхЧеловек часто перечитывает
Hover-паузы200-600 мс перед кликомЕстественная задержка перед действием
МикрокоррекцииДоворот курсора после движенияOvershoot и коррекция

5.2. Полный пример на Puppeteer с использованием всех техник​

JavaScript:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const ghostCursor = require('ghost-cursor');

puppeteer.use(StealthPlugin());

// Функция эмуляции ввода с человеческими задержками
async function humanType(page, selector, text) {
    await page.click(selector);
    await page.waitForTimeout(200 + Math.random() * 300);
    
    for (let i = 0; i < text.length; i++) {
        const char = text[i];
        // Вариативная задержка между символами (50-150 мс)
        const delay = 50 + Math.random() * 100;
        await page.keyboard.type(char, { delay });
        
        // Иногда делаем паузу (человек думает)
        if (Math.random() < 0.05) {
            await page.waitForTimeout(300 + Math.random() * 700);
        }
        
        // Иногда ошибаемся и стираем (опечатки)
        if (Math.random() < 0.02 && i < text.length - 1) {
            await page.keyboard.press('Backspace');
            await page.keyboard.type(char, { delay: delay / 2 });
        }
    }
}

// Основная функция вбива с поведенческой эмуляцией
async function humanLikeCheckout(page, cardData) {
    const cursor = ghostCursor.createCursor(page);
    
    // 1. Естественное движение к первому полю
    const nameField = await page.$('#name');
    const nameBox = await nameField.boundingBox();
    await cursor.moveTo({ x: nameBox.x + 50, y: nameBox.y + 15 });
    await page.waitForTimeout(200 + Math.random() * 300);
    
    // 2. Заполнение полей с человеческими задержками
    await humanType(page, '#name', cardData.name);
    
    // 3. Естественное движение к следующему полю (скролл)
    const cardField = await page.$('#card-number');
    const cardBox = await cardField.boundingBox();
    
    // Имитация прокрутки с переменной скоростью
    await page.evaluate(() => window.scrollBy(0, 200));
    await page.waitForTimeout(100 + Math.random() * 200);
    
    await cursor.moveTo({ x: cardBox.x + 100, y: cardBox.y + 15 });
    await humanType(page, '#card-number', cardData.number);
    
    // 4. Пауза перед отправкой (человек проверяет форму)
    await page.waitForTimeout(800 + Math.random() * 500);
    
    // 5. Клик по кнопке со смещением
    const submitBtn = await page.$('#submit');
    const btnBox = await submitBtn.boundingBox();
    await cursor.moveTo({
        x: btnBox.x + btnBox.width / 2 + (Math.random() - 0.5) * 10,
        y: btnBox.y + btnBox.height / 2 + (Math.random() - 0.5) * 10
    });
    await page.waitForTimeout(200 + Math.random() * 300);
    await page.click('#submit');
}

Часть 6. Метрики оценки неотличимости​

Чтобы проверить, насколько ваш скрипт неотличим от человека, используйте следующие метрики.

6.1. Статистические метрики​

МетрикаКак рассчитываетсяЦелевое значение
Средняя скоростьОбщее расстояние / время движения300-800 пикселей/секунду с вариацией
Коэффициент вариации скоростиStd(скорость) / Mean(скорость)0.3-0.7 (высокая вариативность)
Максимальное ускорениеΔ скорость / Δ время1000-3000 пикселей/с²
Процент прямых сегментовДоля участков с углом поворота < 10°<5% (человек редко движется прямо)

6.2. Шкала доверия (Bot Score)​

Современные системы присваивают каждой транзакции «бот-скор» — число от 0 (определённо человек) до 1 (определённо бот), основанное на вероятности, генерируемой классификатором случайного леса.

Диапазоны бот-скора:
  • 0.0-0.3 → Зелёная зона (человек)
  • 0.3-0.7 → Жёлтая зона (требуется дополнительная проверка)
  • 0.7-1.0 → Красная зона (бот — блокировка)

6.3. Тест Тьюринга для скриптов​

Единственный надёжный способ проверить неотличимость — сравнить траектории вашего скрипта с реальными человеческими траекториями, на которых обучалась система. Для этого можно рассчитать метрики сходства:
Python:
from scipy.spatial.distance import directed_hausdorff
import numpy as np

def similarity_score(trajectory_bot, trajectory_human):
    """
    Рассчёт сходства траектории бота с человеческой
    Возвращает значение от 0 (разные) до 1 (идентичные)
    """
    # 1. Сравнение формы (Hausdorff distance)
    hausdorff_dist = max(
        directed_hausdorff(trajectory_bot, trajectory_human)[0],
        directed_hausdorff(trajectory_human, trajectory_bot)[0]
    )
    
    # 2. Сравнение распределения скоростей
    speeds_bot = np.linalg.norm(np.diff(trajectory_bot, axis=0), axis=1)
    speeds_human = np.linalg.norm(np.diff(trajectory_human, axis=0), axis=1)
    
    speed_similarity = 1 - np.abs(
        np.mean(speeds_bot) - np.mean(speeds_human)
    ) / (np.std(speeds_human) + 1e-6)
    
    # 3. Сравнение распределения углов
    angles_bot = np.arctan2(
        np.diff(trajectory_bot[:,1]), 
        np.diff(trajectory_bot[:,0])
    )
    angles_human = np.arctan2(
        np.diff(trajectory_human[:,1]),
        np.diff(trajectory_human[:,0])
    )
    
    hist_bot, _ = np.histogram(angles_bot, bins=36, range=(-np.pi, np.pi), density=True)
    hist_human, _ = np.histogram(angles_human, bins=36, range=(-np.pi, np.pi), density=True)
    
    angle_similarity = 1 - np.sum((hist_bot - hist_human) ** 2) / 2
    
    # Итоговый скоринг
    return (1 / (1 + hausdorff_dist) * 0.3 + 
            speed_similarity * 0.35 + 
            angle_similarity * 0.35)

Часть 7. Комплексный чек-лист для создания неотличимого скрипта​

Перед запуском скрипта:
  • Собрано минимум 50 реальных сессий через rrweb для создания датасета.
  • LSTM-модель обучена на размеченных человеческих траекториях.
  • Выбраны библиотеки эмуляции (ghost-cursor для Puppeteer, human_mouse/Bumblebee для Python).
  • Настроена вариативность всех параметров: скорость, задержки, ускорения.

Поведенческие параметры для имитации:
  • Движения мыши — кривые Безье + естественные шумы, никаких прямых линий.
  • Hover-паузы — 200-600 мс перед кликом, никогда мгновенных кликов.
  • Пропуск цели (overshoot) — иногда проскальзывайте мимо, затем доворачивайте.
  • Ошибки при вводе — 1-2 опечатки на форму (с последующим исправлением).

После запуска (валидация):
  • Сравните бот-скор с шкалой доверия — должен быть <0.3 для безопасной зоны.
  • Проверьте через тест Тьюринга — визуально сравнив ваши движения с реальными сессиями.
  • Отслеживайте отказы — если всё ещё получаете отказ fraudulent, проблема не в поведении.

Заключение: гонка вооружений продолжается​

Поведенческая биометрия — новейший рубеж в обнаружении автоматизации. С каждым годом эти системы становятся умнее: BioCatch анализирует более 2000 параметров, NuData добивается 99% точности детекции.

Но технологии эмуляции не отстают. Ghost Cursor, LSTM-генерация траекторий и AI-движки вроде Bumblebee делают скрипты всё более неотличимыми от человека. Ключ к успеху — постоянное обновление: каждые 3-6 месяцев рекомендуется пересматривать датасет и переобучать модели на свежих данных.

Три главных вывода:
  1. Статические методы (Canvas, WebGL) уже не главная линия защиты. Поведенческая биометрия — новый рубеж.
  2. Используйте комбинацию библиотек для эмуляции — ни одна не даёт идеального результата в одиночку.
  3. LSTM и RNN — будущее эмуляции. Обучайте свои модели на реальных человеческих сессиях.

Быстрая памятка на одну строку:
«Скорость ≠ монотонная, линии ≠ прямые, клики ≠ мгновенные, ввод ≠ идеальный, паузы ≠ равномерные — и даже тогда ты только приближаешься к человеку»
 
Top