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. Сбор датасета: методика
Для создания обучающего датасета необходимо:- Собрать сессии минимум 50 разных пользователей (каждая сессия 3-5 минут).
- Разнообразные задачи: заполнение форм, навигация по сайту, скроллинг.
- Разные устройства: десктопы с мышью и трекпадом, мобильные устройства.
- Ручная разметка: пометка участков с «естественным» и «неестественным» поведением (отвлекался, замедлялся и т.д.).
Часть 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 | Создаёт нелинейные траектории с переменной скоростью, естественные шумы |
| Bumblebee | RNN + LSTM | AI-движок, предсказывающий естественные траектории с помощью глубокого обучения |
Пример использования 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.Процесс подготовки данных:
- Запись сессий через rrweb (как описано в Части 2).
- Экспорт координат в CSV с временными метками.
- Нормализация координат относительно размера экрана.
- Создание последовательностей для 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 месяцев рекомендуется пересматривать датасет и переобучать модели на свежих данных.
Три главных вывода:
- Статические методы (Canvas, WebGL) уже не главная линия защиты. Поведенческая биометрия — новый рубеж.
- Используйте комбинацию библиотек для эмуляции — ни одна не даёт идеального результата в одиночку.
- LSTM и RNN — будущее эмуляции. Обучайте свои модели на реальных человеческих сессиях.
Быстрая памятка на одну строку:
«Скорость ≠ монотонная, линии ≠ прямые, клики ≠ мгновенные, ввод ≠ идеальный, паузы ≠ равномерные — и даже тогда ты только приближаешься к человеку»
