Pull to refresh

Как сайты обнаруживают ботов по TLS

Level of difficultyMedium
Reading time3 min
Views6.2K

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

HTTP

Протокол передачи гипертекста играет ключевую роль в обмене данными между веб-серверами и браузерами. В запросе мы определяем метод получения ресурса, URI, заголовки и иногда тело запроса. Если повторить все эти параметры, мы получим идентичный ответ. Так ведь? Не всегда! Рассмотрим один из запросов к API "Мегамаркета".

Заголовки запроса
Заголовки запроса
Тело запроса
Тело запроса

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

Проблема точно не в неправильном HTTP-запросе. Сервер иначе определяет, что запрос поступает не от браузера. Чтобы понять, как он это делает, нам нужно разобраться в протоколе, обеспечивающем безопасность в интернете. HTTP передает данные в открытом виде, что делает его пакеты легко подверженными перехвату и изменению. Для обеспечения безопасности соединений был создан HTTPS. Этот протокол - не самостоятельный, а комбинация HTTP и TLS. Именно с TLS нам и предстоит разобраться.

TLS

Transport Layer Security - предоставляет важные услуги безопасности всем приложениям, работающим поверх него, а именно

  • Шифрование – сокрытие информации, передаваемой от одного компьютера к другому;

  • Аутентификация – проверка авторства передаваемой информации;

  • Целостность – обнаружение подмены информации подделкой.

Перед тем, как начать обмен данными через TLS, клиент и сервер должны согласовать параметры соединения, а именно: версию используемого протокола, способ шифрования данных, а также проверить сертификаты, если это необходимо. Схема начала соединения называется TLS Handshake и показана на рисунке. После установки TCP клиент передает в незашифрованном виде спецификацию, указывая, какую версию он использует и какие шифры поддерживает. Сервер утверждает версию используемого протокола, выбирает способ шифрования, прикрепляет свой сертификат и отправляет ответ клиенту. Клиент проверяет присланный сертификат и инициирует обмен ключами. Клиент расшифровывает полученное сообщение. Если всё хорошо, то соединение считается установленным и начинается обмен данными приложений. Если хотите подробно изучить как TLS производит подключение рекомендую эту демонстрацию.

Нас интересует Client Hello так как именно в нём клиент даёт информацию о поддерживаемом шифронаборе. Давайте посмотрим как выглядит ClientHello от браузера через WireShark

Здесь мы видим, что используется TLS 1.2, поддерживается 16 шифронаборов, 8 алгоритмов подписи и 4 эллиптических кривых. Все эти параметры необходимы для криптографии. Однако нас больше интересует, как будет отличаться запрос, например, из Postman.

Этот пакет сильно отличается от предыдущего. Поддерживается 18 шифронаборов, 9 алгоритмов подписи и 3 эллиптических кривых. К тому же в пакете указано что клиент поддерживает совсем устаревшие TLS 1.0 и TLS 1.1

Именно по этим данным сервер понимает что вы заходите не из браузера. Алгоритмы формирования отпечатка могут быть самые разные. Давайте рассмотрим самый популярный.

JA3

JA3 собирает десятичные значения байтов для следующих полей в ClientHello; версия TLS, принятые шифры, список расширений, эллиптические кривые и форматы эллиптических кривых. Затем он объединяет эти значения по порядку, используя "," для разграничения каждого поля и "-" для разграничения каждого значения в каждом поле. Также важно отметить что все поля GREASE не учитываются при формировании отпечатка, а если в ClientHello нет расширений TLS, поля остаются пустыми.

Порядок заполнения полей следующий:

SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat

Затем эта строка хэшируются MD5 для создания легко используемого отпечатка из 32 символов.

Проверить свой JA3 отпечаток вы можете здесь.

Обходим блокировку по отпечатку

Для обхода подобного рода блокировок достаточно использовать шифронаборы соответствующие вашему User-Agent, ну или хотя бы не относящиеся к распространенным HTTP клиентам. Подделать этот отпечаток не так сложно если вы хорошо знаете свой ЯП и посидите с документацией по TLS, но проще использовать готовые библиотеки.

Я в основном использую got-scraping для NodeJS потому что он входит в crawlee который я активно использую. Постараюсь добавлять сюда библиотеки для разных языков.

Golang: CycleTLS

Python: curl_cffi, tls-client

Также можно написать обёртку над curl-impersonate — аналогом curl с возможностью задавать TLS отпечаток.

Заключение

Теперь мы знаем еще один метод для борьбы с парсингом и другими ботами. Следовательно, скоро появится еще N новых методов.

А если вас интересует тема парсинга, буду рад видеть вас в своем телеграм-канале.

Tags:
Hubs:
Total votes 23: ↑22 and ↓1+21
Comments6

Articles