- Регистрация
- 22.02.2015
- Сообщения
- 79
- Благодарностей
- 89
- Баллы
- 18
Как обойти проверку TLS в современных системах защиты Akamai и Cloudflare при выполнении POST/GET-запросов.
Привет! Это моя первая статья на конкурс, хотя в сфере автоматизации я уже более 10 лет. Сегодня хочу поделиться своим опытом и рассказать о решении, которое позволяет успешно работать с сайтами, использующими современные защиты, такие как Akamai и Cloudflare.
Немного теории
В какой-то момент многие сайты, с которыми я работал годами, перестали отвечать на запросы. Поиск причины оказался долгим и утомительным — все запросы через POST/GET стали возвращать ошибку Access Denied. Раньше для обхода подобных блокировок было достаточно корректно передавать User-Agent и другие заголовки. Однако современные системы защиты научились анализировать не только заголовки, но и само взаимодействие клиента с сервером, получая уникальные отпечатки приложения, через которое выполняется запрос.
Например, даже у разных версий Chrome отпечатки TLS отличаются. Таким образом, обычная подмена заголовков уже не помогает, так как теперь необходимо контролировать и эмулировать Client Hello-запросы, в которых содержится уникальный отпечаток браузера. При дальнейших исследованиях стало ясно, что даже с помощью C# полноценно подменить и эмулировать эти данные невозможно.
Что такое Client Hello?
Client Hello — это первое сообщение, которое клиент отправляет серверу при установлении TLS (или SSL) соединения. Оно содержит следующие данные:
Основные параметры:
Дополнительные расширения (Extensions):
Как стало понятно, работать с запросами на таком уровне через стандартные HTTP-клиенты нельзя. Для решения этой проблемы необходимо использовать специализированные инструменты.
Решение проблемы
1. Установка обхода TLS через API
Для обхода современных TLS-защит мы будем использовать tls-client-api. Скачиваем его с GitHub по ссылке: https://github.com/bogdanfinn/tls-client-api/releases
Из списка файлов нам нужны два:
2. Запуск сервера обхода
Запускаем tls-client-api-windows-64-1.8.0.exe. После запуска API будет доступно по адресу: http://127.0.0.1:8080/api/forward
Проверяем работу API в браузере, перейдя по этому адресу. Если сервер успешно запущен, в ответе будет отображаться:
Теперь у нас есть локальный сервер, который позволяет обходить TLS-защиты при выполнении запросов.
3. Выполнение POST/GET запросов через сервер обхода
Выполняем GET запрос к https://tls.peet.ws/api/all:
Привет! Это моя первая статья на конкурс, хотя в сфере автоматизации я уже более 10 лет. Сегодня хочу поделиться своим опытом и рассказать о решении, которое позволяет успешно работать с сайтами, использующими современные защиты, такие как Akamai и Cloudflare.
Немного теории
В какой-то момент многие сайты, с которыми я работал годами, перестали отвечать на запросы. Поиск причины оказался долгим и утомительным — все запросы через POST/GET стали возвращать ошибку Access Denied. Раньше для обхода подобных блокировок было достаточно корректно передавать User-Agent и другие заголовки. Однако современные системы защиты научились анализировать не только заголовки, но и само взаимодействие клиента с сервером, получая уникальные отпечатки приложения, через которое выполняется запрос.
Например, даже у разных версий Chrome отпечатки TLS отличаются. Таким образом, обычная подмена заголовков уже не помогает, так как теперь необходимо контролировать и эмулировать Client Hello-запросы, в которых содержится уникальный отпечаток браузера. При дальнейших исследованиях стало ясно, что даже с помощью C# полноценно подменить и эмулировать эти данные невозможно.
Что такое Client Hello?
Client Hello — это первое сообщение, которое клиент отправляет серверу при установлении TLS (или SSL) соединения. Оно содержит следующие данные:
Основные параметры:
- Версия протокола TLS (например, TLS 1.2 или TLS 1.3);
- Случайное число (Random) (32 байта: 4 байта — Unix timestamp, 28 байт — криптографически случайные);
- Идентификатор сессии (Session ID) (если соединение возобновляется);
- Список поддерживаемых шифров (Cipher Suites) (например, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256);
- Методы сжатия (Compression Methods) (обычно NULL в TLS 1.2 и 1.3).
Дополнительные расширения (Extensions):
- Server Name Indication (SNI) — имя хоста, например example.com;
- Supported Groups (Elliptic Curves) — перечень поддерживаемых эллиптических кривых, например X25519;
- Key Share (TLS 1.3) — отправка публичного ключа;
- Signature Algorithms — поддерживаемые алгоритмы подписи;
- ALPN (Application-Layer Protocol Negotiation) — выбор протокола, например HTTP/2;
- Supported Versions — перечень поддерживаемых версий TLS;
- PSK (Pre-Shared Key) — если используется для возобновления соединения.
Как стало понятно, работать с запросами на таком уровне через стандартные HTTP-клиенты нельзя. Для решения этой проблемы необходимо использовать специализированные инструменты.
Решение проблемы
1. Установка обхода TLS через API
Для обхода современных TLS-защит мы будем использовать tls-client-api. Скачиваем его с GitHub по ссылке: https://github.com/bogdanfinn/tls-client-api/releases
Из списка файлов нам нужны два:
- tls-client-api-windows-64-1.8.0.exe
- config.dist.yml
2. Запуск сервера обхода
Запускаем tls-client-api-windows-64-1.8.0.exe. После запуска API будет доступно по адресу: http://127.0.0.1:8080/api/forward
Проверяем работу API в браузере, перейдя по этому адресу. Если сервер успешно запущен, в ответе будет отображаться:
Код:
{"apiKey":"no api key provided"}
3. Выполнение POST/GET запросов через сервер обхода
Выполняем GET запрос к https://tls.peet.ws/api/all:
Создаем POST запрос по адресу http://127.0.0.1:8080/api/forward.
В данные указываем:
Код:
{
"tlsClientIdentifier": "chrome_105",
"requestUrl": "https://tls.peet.ws/api/all",
"requestMethod": "GET",
"sessionId": "my-custom-sessionid"
}
sessionId указываем, если нужна работа с куками, генерируем рандомную строку. API поддерживает автоматическую работу с куками при указании sessionId.
В заголовки обязательно добавляем:
Код:
x-api-key: my-auth-key-1
Это ключ для доступа к нашему API.
- Для POST запроса аналогичные параметры, только добавляем тело запроса:
Код:
{
"tlsClientIdentifier": "chrome_105",
"requestUrl": "https://tls.peet.ws/api/all",
"requestMethod": "POST",
"sessionId": "my-custom-sessionid",
"RequestBody": "тут передаем тело пост запроса"
}
Дополнительные параметры:
- TlsClientIdentifier — идентификатор клиента (chrome_105);
- FollowRedirects — следовать за редиректами;
- InsecureSkipVerify — игнорировать проверку сертификатов (false);
- IsByteRequest — запрос в байтах (false);
- ForceHttp1 — принудительно использовать HTTP/1.1 (false);
- WithDebug — включить отладку (false);
- WithRandomTLSExtensionOrder — случайный порядок расширений TLS (true);
- sessionId — идентификатор сессии;
- TimeoutSeconds — таймаут в секундах;
- Headers — дополнительные заголовки;
- RequestBody — тело запроса.
- ProxyUrl - прокси формата "http://127.0.0.1:8888"
C#:
/// <summary>
/// Создает экземпляр класса TLSSession для настройки HTTPS-сессии.
/// </summary>
/// <param name="TlsClientIdentifier">Идентификатор клиента TLS (например, для имитации браузера). По умолчанию "FireFox110".</param>
/// <param name="TimeoutSeconds">Таймаут в секундах для выполнения запросов. По умолчанию 30 секунд.</param>
/// <param name="FollowRedirects">Указывает, следует ли автоматически следовать за перенаправлениями (HTTP 3xx). По умолчанию true.</param>
/// <param name="proxy">Прокси-сервер для использования в сессии. По умолчанию null (без прокси).</param>
public TLSSession( string TlsClientIdentifier = "FireFox110", int TimeoutSeconds = 30, bool FollowRedirects = true, string proxy = null)
{
this.Referer = "";
this.headersDefault = new Dictionary<string, string>();
this.cd = new Dictionary<string, string>();
this.sessionID = Guid.NewGuid().ToString();
this.sessionPayload = new RequestPayload
{
TlsClientIdentifier = TlsClientIdentifier,
FollowRedirects = FollowRedirects,
InsecureSkipVerify = false,
IsByteRequest = false,
ForceHttp1 = false,
WithDebug = false,
CatchPanics = false,
WithRandomTLSExtensionOrder = true,
sessionId = this.sessionID,
TimeoutSeconds = TimeoutSeconds,
TimeoutMilliseconds = 0,
CertificatePinningHosts = new Dictionary<string, string>(),
ProxyUrl = "",
IsRotatingProxy = false,
Headers = new Dictionary<string, string>(),
RequestUrl = "",
RequestMethod = "",
RequestBody = "",
RequestCookies = new List<object>(),
};
if (proxy != null)
{
Console.WriteLine(proxy);
this.sessionPayload.ProxyUrl = proxy;
}
}
Что это дает?
Используя tls-client-api, мы можем обойти защиты, такие как Akamai и Cloudflare. Это позволяет работать с сайтом, как будто запросы идут от настоящего браузера, что делает их невидимыми для этих защит. Однако важно понимать, что защита все равно продолжает работать, и если сайт требует валидные куки, то без них запросы все равно не пройдут. Но если у вас есть актуальные куки (например, полученные из браузера), то запросы будут успешно выполняться и вы получите правильные ответы.
Что дальше?
Получение валидных кук — это следующая сложная задача, с которой часто сталкиваются при работе с защищенными сайтами. Это связано с тем, что нужно правильно эмулировать браузер, обходить системы защиты и собирать нужные данные. Я планирую рассказать о том, как генерировать валидные куки, в следующей статье!
Надеюсь, статья будет полезна и интересна!
пример из комментариев
Код:
{
"tlsClientIdentifier": "chrome_133",
"requestUrl": "https://tls.peet.ws/api/all",
"requestMethod": "GET",
"followRedirects": true,
"insecureSkipVerify": false,
"withoutCookieJar": false,
"withDefaultCookieJar": false,
"isByteRequest": false,
"forceHttp1": false,
"withDebug": true,
"catchPanics": true,
"withRandomTLSExtensionOrder": false,
"timeoutSeconds": 30,
"timeoutMilliseconds": 0,
"sessionId": "my-custom-session-id",
"proxyUrl": "",
"isRotatingProxy": false,
"certificatePinningHosts": {
},
"headers": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "ru-RU,ru;q=0.9",
"sec-ch-ua": "\"Chromium\";v=\"133\", \"Not:A-Brand\";v=\"24\", \"Google Chrome\";v=\"133\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"priority": "u=0, i"
},
"headerOrder": [
"sec-ch-ua",
"sec-ch-ua-mobile",
"sec-ch-ua-platform",
"upgrade-insecure-requests",
"user-agent",
"accept",
"sec-fetch-site",
"sec-fetch-mode",
"sec-fetch-user",
"sec-fetch-dest",
"accept-encoding",
"accept-language",
"priority"
],
"requestBody": "",
"requestCookies": [
]
}
Последнее редактирование: