Как антифрод-системы вычисляют прокси по MTU и TCP window scaling
Содержание
- Почему MTU — не просто цифра в 1500
- TCP window scaling — часовой механизм
- Как антифрод собирает эти данные
- Кейс: nginx как прокси и MTU-грабли
- Таблица: типичные window scale factor для разных ОС
- Три реальных кейса
- Когда прокси режет MTU без спроса
- Когда window scaling выдаёт Docker
- Когда клиент использует IPv6 через прокси
- Как проверить свой прокси
- Получаем TCP info через getsockopt
- Linux-specific, работает только на Linux
- Альтернатива - смотрим через /proc
- Пример использования
- Что с этим делать
Прокси-серверы оставляют следы на уровне TCP/IP. Не все, но многие. И антифрод-системы научились снимать отпечатки пальцев с сетевого стека. MTU и TCP window scaling — два параметра, которые выдают прокси с головой.
Почему MTU — не просто цифра в 1500
MTU (Maximum Transmission Unit) — размер пакета, который устройство может отправить без фрагментации. У большинства домашних роутеров — 1500 байт. У серверов в дата-центрах — часто 1500, но с оговорками.
Проблема в пути пакета. Когда клиент шлёт запрос через прокси, MTU может меняться на каждом участке. Антифрод смотрит не на конечное значение, а на то, как клиент реагирует на ICMP-сообщения типа "Fragmentation Needed".
Возьмём реальный пример. Клиент из России через прокси lexic.ml шлёт запрос на сервер в США. Пакет проходит: домашний роутер (MTU 1500) → прокси (MTU 1500) → транзитный узел с MTU 1400. Если прокси не умеет корректно обрабатывать Path MTU Discovery, пакет просто потеряется. Антифрод это видит — клиент ведёт себя не как обычный пользователь.
TCP window scaling — часовой механизм
TCP window scaling — параметр, определяющий размер окна перегрузки. Значение передаётся в SYN-пакете. У разных ОС — разные значения по умолчанию.
Linux 5.x: window scale factor = 7 (128 KiB)
Windows 10: window scale factor = 8 (256 KiB)
macOS: window scale factor = 3 (16 KiB)
Теперь смотрите. Если клиент использует прокси, window scale factor может не совпадать. Типичный кейс: пользователь сидит на Windows 10 (scale 8), но через прокси пакеты идут с scale 7. Антифрод видит несоответствие — это признак туннелирования.
Как антифрод собирает эти данные
Сбор происходит на уровне ядра. Специализированные модули перехватывают TCP-сегменты и анализируют заголовки. Не SYN-пакеты — они легко подделываются. А реальный трафик в установленном соединении.
```bash
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) == 0'
```
Это ловит только SYN-пакеты. Но антифрод смотрит глубже — на последовательность window scaling в течение сессии. Если параметры меняются — это подозрительно.
Кейс: nginx как прокси и MTU-грабли
Пример: сервер на nginx 1.24 настроен как forward proxy. Конфиг:
```nginx
server {
listen 443 ssl;
location / {
proxy_pass http://backend;
proxy_set_header X-Forwarded-For \;
}
}
```
Проблема: nginx по умолчанию не передаёт MTU клиента на бэкенд. Он создаёт новое TCP-соединение со своим MTU. Антифрод на бэкенде видит: клиент прислал запрос с X-Forwarded-For, но MTU пакетов от клиента — 1500, а от nginx — 1460 (типичное значение для PPPoE). Несостыковка.
Решение — форсировать MTU на уровне сокета:
```nginx
stream {
server {
listen 443;
proxy_pass backend:443;
proxy_protocol on;
tcp_nodelay on;
sendfile on;
tcp_nopush on;
}
}
```
Но и это не панацея. Антифрод смотрит на window scale factor в каждом сегменте.
Таблица: типичные window scale factor для разных ОС
| ОС | Window scale factor | Размер окна (байт) |
|---|---|---|
| Linux 5.x | 7 | 131072 |
| Linux 6.x | 7-8 | 131072-262144 |
| Windows 10/11 | 8 | 262144 |
| Windows Server 2022 | 8 | 262144 |
| macOS Ventura | 3 | 65536 |
| FreeBSD 13 | 6 | 65536 |
| iOS 16 | 4 | 65536 |
| Android 13 | 7 | 131072 |
Разброс есть, но внутри одной ОС значения стабильны. Если антифрод видит scale 7 от клиента, который представился Windows — это прокси.
Три реальных кейса
Когда прокси режет MTU без спроса
Пользователь из Испании заходит на сайт через прокси в Нидерландах. Провайдер в Испании использует PPPoE с MTU 1492. Прокси в Нидерландах — чистое Ethernet-подключение с MTU 1500. Когда клиент шлёт пакет размером 1492, прокси его не фрагментирует. Но на обратном пути сервер шлёт пакет 1500 — и он не доходит до клиента, потому что провайдер его режет. Клиент переотправляет запрос, антифрод фиксирует аномальное количество повторных передач. Вердикт — прокси.
Решение — на прокси форсировать MTU 1492:
```bash
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
```
Когда window scaling выдаёт Docker
Контейнерные окружения — отдельная головная боль. Docker использует сетевой стек хоста, но window scale factor может отличаться. Пример: хост на Ubuntu 22.04 с scale 7, а контейнер на alpine — scale 6. Если прокси крутится в Docker, антифрод видит разницу между масштабированием на входящем и исходящем соединении. Несоответствие — триггер.
Проверить можно так:
```bash
cat /proc/sys/net/ipv4/tcp_window_scaling
```
Если 1 — включено. Сам scale factor не выводится, его смотрят через tcpdump.
Когда клиент использует IPv6 через прокси
IPv6 — отдельная песня. Там нет NAT, и MTU discovery работает иначе. Минимальный MTU для IPv6 — 1280 байт. Если прокси не поддерживает корректную обработку ICMPv6 Packet Too Big, клиент просто теряет соединение. Антифрод это видит как обрыв связи и повторные попытки с уменьшенным размером пакета. Типичное поведение для ботов, которые не умеют обрабатывать ICMP.
Как проверить свой прокси
Простой скрипт на Python для анализа window scaling:
```python
import socket
import struct
def get_tcp_window_scale(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect((host, port))
Получаем TCP info через getsockopt
Linux-specific, работает только на Linux
import fcntl
import os
Альтернатива - смотрим через /proc
fd = sock.fileno()
try:
with open(f'/proc/self/fd/{fd}', 'rb') as f:
data = f.read(1024)
except:
pass
sock.close()
Пример использования
get_tcp_window_scale('example.com', 443)
```
Но лучше использовать tcpdump:
```bash
tcpdump -i any -nn 'tcp[tcpflags] & (tcp-syn) != 0 and host target.com and port 443' -X
```
Что с этим делать
Прокси-серверы, которые хотят остаться незамеченными, должны форсировать параметры TCP/IP. Выровнять MTU до значений клиента. Подменить window scale factor под ожидаемую ОС. И главное — не создавать новых TCP-соединений на бэкенд, а пробрасывать существующие.
Но это уже уровень выше. Большинство прокси так не делают. Поэтому антифрод-системы продолжают собирать эти данные и отсеивать подозрительный трафик. Администраторам прокси остаётся только следить за обновлениями и надеяться, что их конкретный стек не попал в базу отпечатков.