Большинство «антиботов» 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%. Идеального фильтра нет: боты с подделанным реферером всё ещё часто проходят, поэтому на статистику стоит смотреть, а не верить на слово.