Как антифрод-системы маркетплейсов связывают аккаунты через MTU и TCP timestamps при работе через один прокси
Содержание
- Почему маркетплейсы смотрят на сетевой уровень
- MTU как отпечаток хоста
- 1472 + 28 (ICMP+IP) = 1500. Если "Frag needed" — MTU меньше.
- В выводе смотрите rtt, rcv_mss, snd_mss
- TCP timestamps: часы, которые тикают одинаково
- 1 — включено, 0 — выключено
- Как это выглядит в логах антифрода
- Почему IPv6 меняет картину
- Что реально связывает аккаунты
- Изоляция на стороне клиента
- Разбор одного подключения
- Практика: что проверять у своего прокси
- MSS и MTU на пути
- TCP options в исходящих
- Timestamps
- Итог
Почему маркетплейсы смотрят на сетевой уровень
Антифрод Wildberries, Ozon, Avito и подобных площадок давно перестал быть набором эвристик на уровне cookie и User-Agent. Современный стек — это комбинация device fingerprinting (Canvas, WebGL, AudioContext), поведенческого анализа и сетевой телеметрии. Последний слой режет большинство «прокси-ферм», потому что на нём палятся даже те, кто аккуратно подменяет отпечаток браузера.
Идея простая: если с одного IP-адреса приходят запросы от десяти «разных» браузеров, но у всех десяти совпадает MTU, TCP timestamp clock rate и набор TCP-опций — вероятность того, что это один физический хост под NAT или один прокси, стремится к единице. Прокси меняет IP, но не меняет то, как ядро Linux или Windows формирует пакеты.
Разберём, что именно утекает и как это ловится.
MTU как отпечаток хоста
Maximum Transmission Unit — максимальный размер полезной нагрузки Ethernet-фрейма, который хост готов принять без фрагментации. Значения по умолчанию сильно различаются между платформами и сетевыми стеками:
| ОС / интерфейс | Типичный MTU |
|---|---|
| Linux Ethernet | 1500 |
| Windows Ethernet | 1500 |
| PPPoE (любая ОС) | 1492 |
| WireGuard | 1420 |
| OpenVPN (tun) | 1500, но PMTU часто 1400–1450 |
| Docker bridge | 1500 |
| macOS Ethernet | 1500 |
Само по себе значение 1500 ничего не говорит. Проблема в том, что прокси-сервер и клиент за ним часто имеют разный MTU, и это видно в TCP-сессиях. Если клиент сидит за VPN с MTU 1420, а прокси отдаёт пакеты с MSS 1460 (1500 − 40 байт заголовков), антифрод видит несоответствие: реальный пользователь из Москвы на домашнем Wi-Fi не может иметь такой паттерн.
Ещё интереснее — MSS clamping. Многие прокси-провайдеры настраивают iptables с `--clamp-mss-to-pmtu`, и тогда все клиенты через этот прокси имеют одинаковый MSS. Десять аккаунтов — один MSS. Это уже сигнал.
Проверить свой MTU и MSS можно так:
```bash
ping -M do -s 1472 -c 1 8.8.8.8
1472 + 28 (ICMP+IP) = 1500. Если "Frag needed" — MTU меньше.
ss -i dst 8.8.8.8
В выводе смотрите rtt, rcv_mss, snd_mss
```
TCP timestamps: часы, которые тикают одинаково
Опция TCP timestamp (RFC 7323) добавляет в каждый сегмент два 32-битных поля: TSval и TSecr. TSval — это текущее значение монотонных часов хоста, обычно с шагом 1 мс, 10 мс или 1 тик в зависимости от `tcp_timestamps` и частоты ядра.
Что важно для антифрода: **TSval растёт линейно и предсказуемо**. По разнице TSval между пакетами можно вычислить uptime хоста с точностью до минут. А по абсолютному значению — сопоставить два соединения, пришедшие с разных IP, но с одного физического хоста.
Пример: клиент подключился через прокси A в 10:00:00 с TSval = 123456789. Через час подключился через прокси B с TSval = 123460389. Разница 3600 секунд при частоте 1000 Гц — идеальное совпадение. Антифрод складывает это в граф связей.
На Linux частота timestamp задаётся `tcp_timestamps` и зависит от `HZ`. На большинстве современных ядер (5.x, 6.x) это 1000 Гц. На Windows — 1000 Гц, но с другими смещениями. На macOS — 1000 Гц, но стартовое значение рандомизируется при загрузке.
Снять timestamps у себя:
```bash
sysctl net.ipv4.tcp_timestamps
1 — включено, 0 — выключено
```
Отключение помогает, но ломает PAWS (Protection Against Wrapped Sequences) и может снизить производительность на длинных fat-pipe соединениях. Не панацея.
Как это выглядит в логах антифрода
Площадки не показывают свои дашборды, но по косвенным признакам (частота блокировок, капчи, требования верификации) можно восстановить логику. Типичный пайплайн:
1. Сбор TCP-заголовков на edge-балансировщике (LVS, nginx stream, HAProxy).
2. Извлечение полей: IP, MSS, window size, TCP options (order и набор), TSval, TSecr.
3. Нормализация и хеширование в «сетевой fingerprint».
4. Кластеризация по fingerprint + поведенческим признакам.
Ключевой момент — **порядок TCP-опций**. Linux, Windows и macOS перечисляют опции в разном порядке и с разным набором. Это уже классический пассивный fingerprint (p0f). Добавьте к этому timestamp clock rate — и вы получите устойчивый идентификатор хоста, который переживает смену IP.
Пример на Python, как выглядит парсинг через scapy:
```python
from scapy.all import sniff, TCP, IP
def fingerprint(pkt):
if TCP in pkt and pkt[TCP].options:
opts = [opt[0] for opt in pkt[TCP].options]
tsval = next((opt[1][0] for opt in pkt[TCP].options if opt[0] == 'Timestamp'), None)
print(f"src={pkt[IP].src} opts={opts} tsval={tsval} win={pkt[TCP].window}")
sniff(filter="tcp and port 443", prn=fingerprint, count=20)
```
На реальном трафике через один прокси вы увидите одинаковые `opts` и почти линейный рост `tsval` для всех «разных» клиентов.
Почему IPv6 меняет картину
В IPv6 заголовок фиксированный (40 байт), опции ушли в extension headers. MSS считается от 1280 (минимальный MTU для IPv6) до 1500 и выше. Провайдеры часто ставят MTU 1500, но туннели (6in4, 6rd, Teredo) дают 1280–1480.
Прокси с поддержкой IPv6 (как lexic.ml) позволяет каждому клиенту получить отдельный /64 или /128, и это снимает проблему «один IP — много аккаунтов». Но MTU и timestamps всё равно утекают, если не изолировать сетевой стек на стороне клиента.
Ключ в том, что IPv6-адрес сам по себе не спасает. Антифрод маркетплейсов уже год как работает с IPv6 не хуже, чем с IPv4. Более того, наличие IPv6 у «домашнего» пользователя из региона, где IPv6 почти не развёрнут (например, часть регионов РФ), — само по себе подозрительно.
Что реально связывает аккаунты
Соберём признаки по убыванию значимости для антифрода:
- **TCP timestamp clock rate и drift** — почти уникален для хоста, переживает смену IP.
- **Порядок и набор TCP options** — фактически отпечаток ОС + версии ядра.
- **MSS** — выдаёт туннели, VPN, нестандартные MTU.
- **Window size и его scaling** — зависит от `tcp_rmem`, часто дефолтный.
- **Начальный ISN (Initial Sequence Number)** — на Linux рандомизирован, но есть корреляции при быстром переподключении.
- **Jitter и RTT** — выдаёт физическое расположение и загрузку канала.
Комбинация первых трёх признаков даёт устойчивый хеш, который антифрод хранит месяцами. Смена прокси, браузера и даже устройства не помогает, если сетевой стек не меняется.
Изоляция на стороне клиента
Единственный способ реально разорвать связь — изолировать сетевой стек для каждого аккаунта. Варианты:
**Network namespaces в Linux.** Каждый namespace имеет свои sysctl, включая `tcp_timestamps`, `tcp_rmem`, `tcp_wmem`. Это даёт разные MSS, window и даже разное поведение timestamps.
```bash
ip netns add acc1
ip netns exec acc1 sysctl -w net.ipv4.tcp_timestamps=0
ip netns exec acc1 sysctl -w net.ipv4.tcp_rmem="4096 65536 4194304"
ip netns exec acc1 curl -x socks5://proxy:1080 https://example.com
```
**Разные ядра / ВМ.** Тяжелее, но эффективнее. Каждая ВМ имеет свой uptime, свои timestamps, свой ISN seed.
**Пользовательские TCP-стеки.** gVisor, lwIP, пользовательские реализации в Go/Rust. Полный контроль над всеми полями, включая рандомизацию TSval.
Первый вариант — минимальный костыль, третий — самый чистый, но требует переписывания клиента.
Разбор одного подключения
Допустим, вы видите в логах два аккаунта с разными IP: 203.0.113.42 и 198.51.100.17. Оба заходят с Chrome 120 на Windows 10, оба из Москвы. Антифрод смотрит на TCP:
```
Conn A: MSS=1460, win=64240, opts=[M,S,TS,N,N,W], TSval=884213
Conn B: MSS=1460, win=64240, opts=[M,S,TS,N,N,W], TSval=884219
```
Разница TSval — 6 мс, при том что соединения разделены минутами реального времени. Это значит, что timestamp clock rate не 1000 Гц, а, скажем, 1 Гц, либо TSval синхронизирован искусственно. В любом случае — оба соединения идут с одного ядра с одинаковыми настройками. Вердикт: связаны.
Если бы у Conn B был MSS=1420 и opts=[M,S,TS,N,W] — это уже другой стек, другая связь, менее очевидная. Но window 64240 совпадает — Linux с дефолтным `tcp_rmem`. Тоже сигнал.
Практика: что проверять у своего прокси
Минимальный чек-лист, если вы гоняете несколько аккаунтов через один прокси:
```bash
MSS и MTU на пути
tracepath -n example.com
TCP options в исходящих
sudo tcpdump -i eth0 -c 5 -vv 'tcp[tcpflags] & tcp-syn != 0' | grep -A2 options
Timestamps
sudo tcpdump -i eth0 -c 5 -vv 'tcp and port 443' | grep timestamp
```
Если видите одинаковые MSS, window и монотонный TSval на всех сессиях — вас свяжут. Не сразу, но при накоплении данных.
Итог
Антифрод маркетплейсов давно ушёл ниже прикладного уровня. IP-адрес — это первое, что меняют, и первое, что перестало быть достаточным. MTU, MSS, порядок TCP-опций и timestamp clock rate формируют отпечаток, который переживает смену IP, cookie и даже браузера. Разрывать эти связи нужно на уровне сетевого стека — через namespaces, отдельные ВМ или пользовательские TCP-реализации. Всё остальное — косметика, которая откладывает блокировку, но не отменяет её.