Большинство «антиботов» 2010-х работают по IP-листам: есть огромная база подозрительных адресов, и если запрос пришёл с одного из них — режем. В 2026 году этого мало: серые IP-пулы стоят копейки, а резидентные прокси дают чистый американский IP за несколько долларов в день. Вдобавок крупные компании раздают пользователям общие адреса — Apple iCloud Private Relay, Google One VPN, — и такие IP выглядят чище, чем адрес в обычном офисе.
IP-листы ловят дешёвых ботов, но средние и продвинутые проходят мимо них. JS-fingerprint смотрит на сам браузер — Canvas, WebGL, шрифты, плагины — и собирает его отпечаток. Поведенческие сигналы (тайминги, прокрутка, движения мыши) дают ещё одну линию обороны. Вместе с проверкой сети это заметно сокращает автоматический трафик, но идеального фильтра нет, и на статистику всё равно нужно смотреть.
Почему IP-блок устарел
Простая арифметика: датацентровый IP стоит пару долларов в месяц, резидентный — несколько долларов в день. Боту, который ворует конверсии в партнёрке с выплатой $5, хватает одного-двух успешных лидов, чтобы окупить день работы. Бан по IP — это игра «прибей крота», где у вас один молоток, а у бота тысячи нор.
Что ещё проигрывают чистые IP-листы:
- Мобильные операторы — десятки тысяч пользователей за одним NAT.
- Корпоративные сети — банить нельзя, внутри реальные пользователи.
- Apple iCloud Private Relay — скрывает IP, при этом за ним обычные люди.
- Headless-браузеры с резидентными прокси — выглядят как обычный пользователь Mac в Чикаго.
Что такое JS-fingerprint
Идея: каждый браузер уникален в мелочах. Версия движка, набор шрифтов, видеокарта, аудиостек, разрешение экрана, часовой пояс, плагины. По отдельности это банальные параметры, вместе — отпечаток с энтропией около 30 бит и больше. Этого хватает, чтобы различать миллиард пользователей.
Примерно такие сигналы собирает скрипт на стороне клиента:
// упрощённый набор сигналов
{
canvas: hash(canvasRender("TDS-probe", "Inter 16px")),
webgl: hash(gl.getParameter(gl.RENDERER) + gl.getParameter(gl.VENDOR)),
audio: hash(offlineAudioContext.fingerprint()),
fonts: detectAvailableFonts(['Inter', 'Roboto', ...]),
screen: { w, h, depth, dpr },
navigator: { ua, platform, lang, hwConcurrency, memory },
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
plugins: navigator.plugins.length,
webdriver: !!navigator.webdriver, // признак headless-браузера
permissions: queryPermissions(['notifications', 'geolocation'])
}
Сам по себе отпечаток ничего не решает — важно, сходится ли он с тем, что браузер говорит о себе. Если User-Agent обещает iPhone, а WebGL показывает программную отрисовку без видеокарты, или включён navigator.webdriver, — перед нами скорее автоматизация, чем человек.
Поведенческие сигналы
Отпечаток статичен. А поведение — нет. Headless-браузер не двигает мышь как человек, не прокручивает страницу «рваными» жестами, не задерживается на ней пару секунд перед кликом. Эти сигналы дают ещё один слой:
| Сигнал | Что наблюдаем | Бот выдаёт |
|---|---|---|
| mousemove | кривая, ускорения | прямая, мгновенная |
| scroll | тайминги, дельты | равномерный или нет |
| click | координаты относительно элемента | ровно в центр элемента |
| focus/blur | время на странице | < 500 мс |
| keypress | тайминг между нажатиями | постоянный или 0 |
Скоринг и решения
Все сигналы складываются в одну вероятность того, что перед нами бот. Решение принимается не по принципу «бот / не бот», а по порогам:
- ниже 0.5: чистый трафик, пускаем на оффер.
- 0.5–0.7: сомнительный визит, показываем CAPTCHA; кто её прошёл, идёт дальше.
- 0.7 и выше: бот, отправляем на страницу по умолчанию для нецелевого трафика, которую выбрали вы: свой адрес, лендинг или код ответа.
Компромиссы метода
JS-fingerprint не идеален. Честно перечислим минусы:
- Лишний запрос: нужен JavaScript на стороне клиента, а это добавляет задержку. Проверку можно сделать короткой, но совсем без неё не обойтись.
- Браузеры с отключённым JavaScript: их можно оценить только по сети, заголовкам и спискам.
- Режимы приватности: Brave, строгий режим Firefox, Tor подменяют часть отпечатка. По одному отпечатку таких посетителей не оценить, поэтому решение складывается из всех проверок сразу.
- Ложные срабатывания: часть реальных пользователей попадает в зону CAPTCHA. Решив её, они проходят дальше, но часть отваливается.
Что мы используем в TDS
Антибот TDS.SO проверяет каждый клик по порядку: правила и списки → сеть → фингерпринт и поведение → общий вердикт ансамбля.
- Правила и списки: свои белые и чёрные списки IP и User-Agent, разрешённые рефереры, пустой UA, уровни фильтра от 0 до 3.
- Сеть: IP дата-центров, прокси, выходные узлы TOR, публичные списки IP-репутации.
- Фингерпринт и поведение: WebGL и canvas, признаки headless-браузеров, navigator.webdriver и инструменты автоматизации, траектория движения мыши.
- Вердикт ансамбля: сигналы всех проверок сводятся в одну вероятность — от 0.5 показывается CAPTCHA, от 0.7 клик считается ботом.
Сколько трафика отсеяно, видно в статистике по каждой ссылке. За последние 90 дней через TDS.SO прошло около 45,8 млн кликов клиентов, и фильтр отсеивал в среднем около 31,6%. Идеального фильтра нет: боты с подделанным реферером всё ещё часто проходят, поэтому на статистику стоит смотреть, а не верить на слово.