Как работает утечка через WebRTC
Принцип работы WebRTC
Антифрод не «узнаёт» ваш настоящий IP каким-то отдельным запросом. Он сравнивает два адреса: тот, с которого пришла TCP-сессия, и тот, который браузер сам сообщает через WebRTC поверх UDP. Расхождение между ними и есть сигнал.
Механика проверки
Одинакова для всех трёх сценариев:
- Браузер открывает страницу через SOCKS5-прокси. Весь HTTP/HTTPS идёт по TCP, сайт видит IP прокси.
- Антифрод отдаёт странице скрипт, который создаёт
RTCPeerConnectionи указывает свой STUN- или TURN-сервер вiceServers. - Браузер начинает собирать ICE-кандидатов и шлёт на этот сервер STUN Binding Request по UDP.
- STUN-сервер отвечает
Binding Responseс атрибутомXOR-MAPPED-ADDRESS. В нём указан публичный адрес источника пакета. Браузер превращает его в srflx-кандидата. - Скрипт ловит кандидата в
onicecandidate, вытаскивает из него IP и сравнивает с адресом TCP-сессии.
Ключевой момент - шаг 3. Пойдёт ли этот UDP-пакет через прокси или мимо него, решают две вещи: поддерживает ли прокси UDP и умеет ли браузер туда UDP отдавать. Отсюда и три исхода.
Сценарий 1. Прокси передаёт UDP, адреса совпадают
- TCP-сессия идёт через SOCKS5-прокси, сайт видит
198.51.100.7. - Антифрод подсовывает скрипт со своим STUN-сервером.
- Браузер открывает UDP-ассоциацию через тот же прокси (
UDP ASSOCIATE, RFC 1928) и отправляет Binding Request уже из него. - STUN видит адрес прокси и возвращает его же в
XOR-MAPPED-ADDRESS:198.51.100.7. - Скрипт сравнивает: IP TCP-сессии и srflx-кандидат совпали.
Итог: WebRTC работает штатно, кандидаты есть, адреса одинаковые. Профиль выглядит как обычный пользователь, потому что он им и выглядит на уровне сети.
Для этого нужны две вещи одновременно: прокси с поддержкой UDP ASSOCIATE и клиент (браузер или антидетект), который реально маршрутизирует WebRTC-трафик в прокси, а не в обход.
Сценарий 2. UDP обходит прокси и раскрывает реальный адрес
- TCP-сессия идёт через прокси, сайт видит
198.51.100.7. - Антифрод подсовывает скрипт со своим STUN-сервером.
- Браузер шлёт Binding Request напрямую с сетевого интерфейса, минуя прокси.
- STUN видит настоящий адрес
113.22.13.2и возвращает его как srflx-кандидата. - Скрипт сравнивает:
113.22.13.2≠198.51.100.7. Прокси обнаружен, настоящий IP получен.
Итог: утечка. Причём антифрод получает не просто «подозрительный» признак, а конкретный адрес.
Почему UDP уходит мимо:
- прокси поддерживает только TCP: HTTP-прокси через
CONNECTумеет передавать только TCP, как и SOCKS5 безUDP ASSOCIATE; - прокси поддерживает UDP, но браузер не направляет в него UDP: Chrome по умолчанию не передаёт WebRTC-трафик через настроенный прокси и отправляет его напрямую;
- прокси поднят только для конкретного профиля/расширения, а WebRTC работает на уровне всего процесса.
Если STUN/TURN-сервер в iceServers контролирует сам антифрод, ему даже не нужен шаг 5. Он видит настоящий адрес непосредственно в адресе источника входящего UDP-пакета.
Локальные адреса (192.168.*, 10.*) здесь почти не играют роли. Начиная с Chrome 80 host-кандидаты передаются как mDNS-имена вида <uuid>.local, поэтому получить данные о локальной сети через WebRTC стало сложнее. В этом сценарии раскрывается именно публичный srflx-адрес.
Сценарий 3. Браузер блокирует WebRTC: утечки нет, но это заметно
- TCP-сессия идёт через прокси, сайт видит
198.51.100.7. - Антифрод подсовывает скрипт со своим STUN-сервером.
RTCPeerConnectionзаблокирован расширением, флагом браузера или подменённым API в антидетекте. STUN-запрос не уходит ни через прокси, ни напрямую.- Отвечать некому:
onicecandidateне срабатывает, сбор кандидатов заканчивается пустым списком. - Скрипту нечего сравнивать.
Итог: настоящий IP не утёк. Однако антифрод видит другую аномалию: современный Chrome на настольном компьютере, в котором WebRTC полностью отсутствует. У большинства обычных пользователей он включён, поэтому пустой список кандидатов повышает оценку риска, как и любое другое несоответствие заявленного user-agent реальному поведению API.
То есть выключение WebRTC меняет утечку адреса на аномалию отпечатка. Иногда это приемлемый размен, но это именно размен, а не решение.
Обновлено