Как антифрод TikTok вычисляет IPv6-прокси по TLS-отпечатку и метрикам тайминга
Содержание
- Что вообще видят серверы TikTok
- TLS-отпечаток: что реально собирают в 2024
- HTTP/2 fingerprint: псевдозаголовки и приоритеты
- Тайминги: где IPv6-прокси выдаёт себя
- Кейс: датацентровый IPv6-пул и его провал
- Кейс: рассинхрон TLS и User-Agent
- Кейс: тайминги выдали туннель
- Таблица: что проверяет антифрод и как это обойти
- Почему IPv6 сложнее, чем IPv4
- Практика: как проверить свой прокси перед боем
- Что делать с HTTP/2-приоритетами
- Итог: что реально работает
TikTok собирает больше сигналов, чем кажется. Пользователь видит ленту, а на бэкенде в это время крутится конвейер из десятков проверок. Прокси прячет IP. Остальное остаётся голым.
Разберём, что именно смотрят их системы, как отличить хороший IPv6-туннель от мусора и почему один только JA3 уже не спасает.
Что вообще видят серверы TikTok
Первый слой — сетевой. IP, ASN, геолокация, наличие IPv6, совпадение с заявленным регионом аккаунта. Второй — транспортный: TLS handshake, порядок расширений, набор шифров, ALPN. Третий — прикладной: заголовки HTTP/2, порядок псевдозаголовков, приоритеты потоков. Четвёртый — поведенческий: тайминги запросов, интервалы между нажатиями, движение скролла.
Прокси решает только первую задачу. Всё остальное либо совпадает с реальным устройством, либо выдаёт.
Ключевая проблема IPv6-прокси в том, что пул адресов часто маленький. Один /64 на сотню клиентов — и антифрод видит, что с этой подсети за сутки логинилось 300 разных аккаунтов с разных устройств. Это не приговор, но флаг.
TLS-отпечаток: что реально собирают в 2024
JA3 — это MD5 от строки с версией TLS, списком шифров, расширений, эллиптических кривых и форматов точек. Устарел, но всё ещё используется. JA4 — новее, учитывает ALPN и SNI, стабильнее к рандомизации.
Вот как выглядит типичный JA3 curl:
```
771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0
```
Python requests с urllib3 даёт другой отпечаток. Go-клиент — третий. Chrome 120 — четвёртый. Если аккаунт заявлен как «iPhone с Safari», а TLS-отпечаток соответствует Python 3.11 + requests 2.31 — это красный флаг сразу.
Проверить свой отпечаток можно так:
```bash
curl -s https://tls.peet.ws/api/all | jq '.tls.ja3_hash, .tls.ja4, .http2.akamai_fingerprint'
```
Ответ покажет JA3, JA4, Akamai HTTP/2 fingerprint. Сравните с тем, что отдаёт реальный браузер на том же устройстве. Расхождение — первый признак, что вас вычислят.
HTTP/2 fingerprint: псевдозаголовки и приоритеты
Akamai придумал схему fingerprinting для HTTP/2 ещё в 2017. Смысл: разные клиенты отправляют SETTINGS-фрейм с разными параметрами, по-разному упорядочивают псевдозаголовки `:method`, `:path`, `:authority`, `:scheme`, по-разному выставляют приоритеты.
Chrome ставит `:method`, `:authority`, `:scheme`, `:path`. Firefox — другой порядок. Python httpx — третий. Go net/http — четвёртый.
Формат Akamai fingerprint: `settings|window_update|priority|pseudo_headers`. Например, у Chrome 120 это что-то вроде `1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p`.
Если ваш прокси-клиент отдаёт Go-отпечаток, а User-Agent заявляет Chrome — детект сработает за миллисекунды. Никакой IPv6 не спасёт.
Тайминги: где IPv6-прокси выдаёт себя
TCP handshake через IPv6-прокси занимает больше времени, чем напрямую. Причина — дополнительный хоп до прокси-сервера. Если сервер в Нидерландах, а клиент в Москве, RTT до TikTok-эджа может вырасти с 40 мс до 90-120 мс.
TikTok измеряет несколько метрик:
- TCP handshake time (SYN → SYN-ACK)
- TLS handshake time (ClientHello → Finished)
- TTFB (time to first byte)
- Межзапросовые интервалы
Первый и второй — самые показательные. На хорошем прямом соединении TLS handshake укладывается в 1 RTT. Через прокси с плохой настройкой — в 2-3 RTT. Разница в 50-150 мс на handshake — заметный сигнал.
Вот как замерить:
```bash
curl -w "dns: %{time_namelookup} connect: %{time_connect} tls: %{time_appconnect} ttfb: %{time_starttransfer} total: %{time_total}\n" -o /dev/null -s https://www.tiktok.com/
```
Прогоните 20 раз через прокси и 20 раз напрямую. Если медиана `time_appconnect` через прокси выше на 60+ мс — это уже подозрительно. Особенно если геолокация IP заявлена как «Германия», а RTT до немецкого эджа TikTok у вас 180 мс. Немец с немецким IP такого RTT не получит.
Кейс: датацентровый IPv6-пул и его провал
Пример: сервер на Ubuntu 22.04, nginx 1.24 как reverse proxy, за ним Python-скрипт на httpx 0.25. Пул — /64 из датацентра Hetzner, 200 адресов, ротация round-robin.
Проблема: TikTok начал требовать капчу на каждом третьем логине. Аккаунты регистрировались нормально, но через 2-3 дня уходили в теневой бан.
Причина: ASN Hetzner (AS24940) давно в чёрных списках как датацентровый. Плюс /64 светился в сотнях запросов от разных «устройств» с одинаковым TLS-отпечатком httpx. Плюс RTT до TikTok-эджа стабильно 95-110 мс при заявленной геолокации Германия — реальный немец получает 15-25 мс.
Решение: переехали на residential IPv6-пул (не датацентр), распределили по /56 вместо /64, каждый клиент получил свой /64 из большого блока. Заменили httpx на curl_cffi с имперсонацией Chrome 120. RTT упал до 30-40 мс через немецкий эдж.
Капча ушла на 90%. Не полностью — TikTok всё равно иногда проверяет, но уже не каждый третий логин.
Кейс: рассинхрон TLS и User-Agent
Другая история. Клиент настроил ротацию User-Agent: то iPhone Safari, то Android Chrome, то десктопный Firefox. Прокси — обычный SOCKS5 через IPv6-туннель. Запросы шли через Python requests 2.31.
Проблема: через сутки все аккаунты получили запрос на верификацию телефона.
Причина: Python requests всегда отдаёт одинаковый TLS-отпечаток, независимо от User-Agent. Антифрод увидел, что «iPhone Safari» имеет JA3, идентичный «Android Chrome» и «Firefox». Такое в реальности невозможно — у трёх разных браузеров три разных отпечатка.
Плюс HTTP/2 fingerprint был одинаковый для всех трёх «устройств». Плюс порядок заголовков в HTTP-запросе соответствовал Python, а не браузеру.
Решение: перешли на реальные браузерные отпечатки через curl_cffi с параметром `impersonate="chrome120"` и `impersonate="safari17_0"` для соответствующих аккаунтов. Проверили через tls.peet.ws, что JA3 и Akamai fingerprint совпадают с эталоном. Верификация ушла.
Кейс: тайминги выдали туннель
Третий пример. Прокси-сервер в Сингапуре, клиент в Москве, аккаунт заявлен как сингапурский. Всё чисто: IPv6 residential, TLS-отпечаток Chrome, HTTP/2 fingerprint совпадает.
Проблема: TikTok ограничивал охваты. Видео публиковались, но в рекомендации не попадали.
Причина: медиана RTT до TikTok-эджа — 175 мс. Реальный сингапурец получает 8-20 мс. Плюс jitter — колебания задержки — 40-60 мс. Это выдаёт длинный маршрут через полмира. Антифрод пометил аккаунт как «вероятно через прокси», охваты урезал.
Решение: переехали на прокси в том же регионе, что и клиент (Москва → европейская часть РФ или ближнее зарубежье), заявили геолокацию соответственно. RTT упал до 25-35 мс, jitter до 5-8 мс. Охваты восстановились.
Здесь важен принцип: IP-геолокация, RTT и заявленный регион аккаунта должны совпадать. Иначе даже идеальный TLS-отпечаток не поможет.
Таблица: что проверяет антифрод и как это обойти
| Сигнал | Что смотрят | Как проверить | Как исправить |
|---|---|---|---|
| JA3/JA4 | Порядок шифров, расширения | tls.peet.ws | curl_cffi с impersonate |
| HTTP/2 fingerprint | SETTINGS, порядок заголовков | tls.peet.ws | Тот же curl_cffi |
| TCP handshake | Время SYN→SYN-ACK | curl -w time_connect | Прокси ближе к клиенту |
| TLS handshake | Время ClientHello→Finished | curl -w time_appconnect | Быстрый прокси, TLS 1.3 |
| RTT до эджа | Медиана и jitter | Пинг через прокси | Прокси в регионе аккаунта |
| ASN | Датацентр vs residential | whois, ipinfo.io | Residential IPv6-пул |
| Размер подсети | Сколько адресов в /64 | ip -6 route | /56 или больше |
| User-Agent vs JA3 | Совпадение браузера | Сравнение с эталоном | Имперсонация реального браузера |
Почему IPv6 сложнее, чем IPv4
С IPv4 прокси всё проще: берёшь residential-адрес, ротируешь, следишь за репутацией. С IPv6 есть нюанс — адресов так много, что провайдеры часто выдают целые /64 или /48. И антифрод это знает.
Если с одного /64 идёт трафик от 50 «разных устройств» — это очевидный прокси. Реальный провайдер выдаёт /64 одному домашнему роутеру, за которым 3-5 устройств. Не 50.
Поэтому грамотный IPv6-прокси-сервис раздаёт каждому клиенту свой /64 из большого пула. Тогда подсеть выглядит как обычный домашний роутер. Именно так работает lexic.ml — residential-подход к IPv6 с изоляцией подсетей, что снижает вероятность попадания в общий бан-лист.
Второй нюанс — IPv6-префиксы в чёрных списках. Некоторые ASN уже помечены как «прокси-френдли». Проверить ASN можно через ipinfo.io:
```bash
curl -s https://ipinfo.io/2a01:4f8:1c1c:abcd::1/json | jq '.org, .asn'
```
Если ASN принадлежит хостингу — ждите проблем. Если residential-провайдеру — шансы выше.
Практика: как проверить свой прокси перед боем
Соберите чек-лист и прогоните перед запуском аккаунтов. Ниже — минимальный скрипт проверки.
```python
import subprocess
import statistics
import json
def check_proxy(proxy_url, target="https://www.tiktok.com/"):
times = []
for _ in range(10):
result = subprocess.run(
["curl", "-x", proxy_url, "-w", "%{time_appconnect}",
"-o", "/dev/null", "-s", target],
capture_output=True, text=True
)
times.append(float(result.stdout))
fp = subprocess.run(
["curl", "-x", proxy_url, "-s", "https://tls.peet.ws/api/all"],
capture_output=True, text=True
)
data = json.loads(fp.stdout)
return {
"tls_median_ms": round(statistics.median(times) * 1000, 1),
"tls_jitter_ms": round(statistics.stdev(times) * 1000, 1),
"ja3": data["tls"]["ja3_hash"],
"ja4": data["tls"]["ja4"],
"h2_fp": data["http2"]["akamai_fingerprint"],
"ip": data["ip"],
}
print(check_proxy("socks5h://user:pass@[2a01:4f8::1]:1080"))
```
Что смотреть в выводе:
- `tls_median_ms` до TikTok-эджа — меньше 60 мс для европейского аккаунта, меньше 40 мс для азиатского
- `tls_jitter_ms` — меньше 15 мс, иначе маршрут нестабильный
- `ja3` и `ja4` — должны совпадать с эталоном браузера, под который маскируетесь
- `h2_fp` — то же самое
- `ip` — проверьте через whois, что это не датацентр
Если хоть один пункт выпадает — не запускайте аккаунты. Сначала почините.
Что делать с HTTP/2-приоритетами
Отдельная боль — приоритеты потоков в HTTP/2. Chrome отправляет PRIORITY-фреймы с определённой структурой. Python httpx — вообще не отправляет. Go — отправляет, но по-другому.
TikTok смотрит на это. Если клиент не отправляет PRIORITY-фреймы, но заявляет Chrome — детект.
Решение — использовать библиотеки с полной имперсонацией. curl_cffi делает это на уровне libcurl с патчами. Есть также tls-client (Go), bogdanfinn/tls-client. Все они воспроизводят не только TLS, но и HTTP/2-поведение.
Проверка через tls.peet.ws покажет `http2.sent_frames` — список отправленных фреймов. У Chrome там будет PRIORITY, у httpx — нет.
Итог: что реально работает
Антифрод TikTok — многослойный. IPv6-прокси закрывает только сетевой слой. Дальше нужна работа с TLS, HTTP/2 и таймингами.
Работающая связка выглядит так: residential IPv6-пул с изоляцией /64 на клиента, прокси в регионе аккаунта, RTT до эджа меньше 60 мс, curl_cffi с имперсонацией реального браузера, консистентный User-Agent и TLS-отпечаток.
Что ломается чаще всего: датацентровые ASN, общий /64 на десятки клиентов, Python requests без имперсонации, рассинхрон User-Agent и JA3, большой RTT при заявленной близкой геолокации.
Проверяйте каждый прокси перед запуском. Один прогон скрипта выше экономит недели восстановления аккаунтов.