Перейти к содержанию
понедельник, 27 июля 2026 г.

ИИ Вестник

Главные новости о развитии искусственного интеллекта в России

Обход антибот-защиты на уровне TLS: как имитация Chrome позволяет собирать данные с российских сайтов

Developer imitating Chrome to bypass TLS anti-bot protection on Russian sites.
Generated by Sourceful Riverflow (RouterAI)

Разработчик, собирающий данные с Яндекс.Афиши и afisha.ru, столкнулся с блокировкой даже при корректных HTTP-заголовках. Проблема оказалась на транспортном уровне: стандартные Python-клиенты палятся по TLS-рукопожатию, которое отличается от браузерного. Решение нашлось в библиотеке curl_cffi, воспроизводящей полный профиль Chrome, однако дальнейшие тесты выявили дополнительные слои защиты.

В процессе создания единой карты афиш города по пяти источникам разработчик обнаружил, что два ключевых ресурса — Яндекс.Афиша и afisha.ru — систематически отклоняют запросы, отправленные через стандартный Python-клиент. Даже после копирования всех заголовков из браузера, включая User-Agent и sec-ch-ua, вызов requests.get возвращал HTTP-статус 403, при этом никаких капч или форм подтверждения не появлялось. Первоначальные догадки о нехватке куки или специфичных заголовков не подтвердились: оказалось, что блокировка происходит до того, как сервер успевает прочитать User-Agent, а именно на этапе установки защищённого соединения. Этот случай иллюстрирует типичный для современного веба сдвиг: антибот-системы всё чаще анализируют не только содержание запроса, но и саму манеру установки соединения, используя TLS-фингерпринты (JA3, JA4) для различения типов клиентов ещё на транспортном уровне.

HTTPS-соединение начинается с TLS-рукопожатия, в ходе которого клиент отправляет серверу сообщение ClientHello, содержащее список поддерживаемых версий TLS, порядок шифров, эллиптические кривые, расширения и ALPN. Эта совокупность параметров формирует уникальный TLS-фингерпринт, известный как JA3 или более новый JA4. В типовой сборке Python использует модуль ssl поверх OpenSSL, тогда как Chrome — BoringSSL (форк OpenSSL от Google). Отличия наблюдаются практически во всём: наборе и очерёдности шифров, TLS-расширениях, GREASE, версии HTTP, а также в настройках HTTP/2 SETTINGS и порядке псевдозаголовков. Таким образом, строка User-Agent: Mozilla/5.0... сама по себе не доказывает браузерного происхождения запроса — антибот-система уже получила сильный сигнал транспортного уровня, указывающий на OpenSSL-профиль, не свойственный Chrome. Инструменты вроде ja3er.com позволяют легко проверить собственный отпечаток, и у Python-клиента он будет кардинально отличаться от браузерного.

Эксперимент с несколькими конфигурациями клиента при неизменных IP и URL показал, что замена HTTP-заголовков не повлияла на статус ответа. Проблема решилась только при использовании browser impersonation с помощью библиотеки curl_cffi — обёртки над curl-impersonate. Эта библиотека воспроизводит полный транспортный профиль браузера: TLS-параметры, ALPN и характерное HTTP/2-поведение конкретной версии Chrome. Одна строка impersonate="chrome" в коде на Python заставила серверы Яндекс.Афиши и afisha.ru принять соединение, которое ранее блокировалось. В отличие от Selenium или Puppeteer, curl_cffi не требует тяжёлого браузерного движка, работает значительно быстрее и проще в развёртывании. Однако стоит помнить, что это не универсальный ключ: другие библиотеки (например, pycurl с кастомными опциями или python-tls-client) также могут подменять TLS-профиль, но каждая имеет свои особенности. Важно, что чистота теста не была абсолютной — вместе с TLS-профилем менялись и HTTP/2-параметры, поэтому точный вклад каждого слоя остаётся не разделённым.

Однако оказалось, что это лишь первый этап: после успешного рукопожатия POST-запрос к GraphQL-эндпоинту Яндекс.Афиши продолжал получать статус 405, пока разработчик не выяснил, что обязательно требуется пустой заголовок x-csrf-token, корректные origin и referer, а также валидная кука yandexuid. Этот статус часто ассоциируют с неверным HTTP-методом, но на практике он может быть результатом проверки структуры запроса на уровне API или middleware. В данном случае сервер ожидал точного фронтенд-шаблона — пустой CSRF-токен, конкретные origin и referer, а также определённый GraphQL-оператор. Без них запрос не доходил до бизнес-логики, хотя транспортное соединение уже было принято. Такие скрытые проверки — распространённый приём: антибот-системы могут имитировать разные статусы ошибок, чтобы затруднить отладку.

Даже после прохождения транспортного профиля и настройки POST-запроса afisha.ru могла возвращать капчу при запросах с IP-адресов дата-центров. В данном случае блокировка была обусловлена не транспортным профилем, а репутацией диапазона: провайдер VK Cloud оказался «грязным» с точки зрения сервиса. Для обхода этого слоя разработчику пришлось настроить WireGuard-туннель с выходом через GCP, причём особенность WireGuard — необходимость указывать IP-префиксы, а не домены — потребовала резолвинга домена afisha.ru в конкретные адреса. Этот кейс демонстрирует, что антибот-системы часто комбинируют множество сигналов: TLS-фингерпринт, HTTP/2 профиль, репутацию IP и ASN, куки, историю сессии, JS-челленджи и поведенческий анализ. Некоторые провайдеры, как Cloudflare, активно используют все эти слои, и обход каждого требует отдельной техники.

Для российского рынка скрейпинг данных — частая задача при создании агрегаторов, мониторинга цен и сбора афиш. Такие сайты, как Яндекс.Афиша и afisha.ru, активно используют защиту, которая эволюционирует от простых капч к анализу на транспортном уровне. Подход с имитацией браузера через curl_cffi даёт более лёгкую и быструю альтернативу полноценным браузерным движкам вроде Selenium или Puppeteer, которые потребляют много ресурсов и проще детектируются по версии драйвера. Однако он требует глубокого понимания TLS-отпечатков и постоянной подстройки под изменения в антиботах, например, при обновлении версий Chrome, меняющих порядок шифров или GREASE. Сравнение с коммерческими сервисами, такими как ScrapingBee или Crawlbase, показывает, что самодельное решение на curl_cffi позволяет сэкономить, но уступает в стабильности: провайдеры таких услуг поддерживают актуальные профили браузеров и управляют ротацией IP. Разработчик также подчёркивает, что нельзя делать однозначные выводы по HTTP-статусам: код 403 может быть вызван TLS-отпечатком, WAF-правилом, репутацией IP или лимитами частоты, а 405 — не обязательно ошибка метода, а проверка наличия определённых заголовков. Для отладки полезнее спрашивать, на каком слое произошла блокировка, а не полагаться на номер ошибки.

Перспектива развития антибот-систем заключается в умножении проверок: помимо TLS и HTTP/2 они всё чаще используют JavaScript-челленджи, анализ времени нажатий, мыши и скролла, а также машинное обучение для выявления аномалий. Универсального решения не существует, и разработчикам скрейперов приходится выбирать между скоростью (имитация транспортного уровня) и надёжностью (полная эмуляция браузера). Открытым остаётся вопрос, как долго будут работать методы типа curl_cffi и не потребуются ли в ближайшем будущем более сложные подходы, включая использование реальных браузеров с подменой отпечатков или распределённые сети доверенных узлов. Пока что успех в обходе защиты зависит от умения анализировать конкретную комбинацию сигналов, применённую на целевом сайте, и оперативно адаптироваться под новые версии браузеров и антибот-алгоритмы.

Читайте также