← Назад в базу знаний

Ловушка WebRTC: как браузер сливает реальный IP даже при включённом VPN и прокси

Ловушка WebRTC: как браузер сливает реальный IP даже при включённом VPN и прокси

WebRTC — технология, которая делает видеозвонки и файлообмен без установки плагинов. Работает она через UDP, обходит NAT, использует ICE-кандидаты. И вот тут начинается веселье: браузер собирает все доступные IP-адреса машины и отправляет их на сервер-собеседник. Даже если ты сидишь через VPN или прокси.

Как WebRTC узнаёт твой IP

Механизм простой. Браузер запрашивает у операционной системы все сетевые интерфейсы. Не только тот, через который идёт трафик к VPN-серверу, но и локальные адреса, адреса виртуальных адаптеров, адреса в подсети роутера. Всё это пакуется в SDP-оффер и улетает на сигнальный сервер.

Вот как выглядит типичный ICE-кандидат:

```

candidate:842163049 1 udp 1677729535 192.168.1.37 52345 typ host

candidate:842163050 1 udp 1677729535 10.8.0.2 52346 typ host

candidate:842163051 1 udp 1677729535 85.142.12.7 52347 typ srflx

```

Третий кандидат — это рефлексивный адрес, который STUN-сервер возвращает. Если VPN настроен правильно, тут будет IP VPN-сервера. Но первые два — локальные. И они видны всем.

STUN и TURN: почему не работает просто прокси

Прокси работает на уровне HTTP. Он передаёт запросы и ответы, но не трогает UDP. WebRTC использует UDP для медиатрафика. Прокси для этого бесполезен.

STUN-сервер нужен, чтобы узнать свой внешний адрес. Браузер шлёт запрос на STUN, тот отвечает: "твой публичный IP — 203.0.113.5". Если ты за VPN, STUN вернёт IP VPN-сервера. Но браузер не ограничивается одним запросом. Он шлёт STUN-запросы через каждый сетевой интерфейс. И если VPN-клиент пропускает трафик мимо туннеля (split tunneling) или в системе есть второй активный адаптер — утечка.

TURN-сервер — это ретранслятор. Он принимает медиатрафик и пересылает его собеседнику. TURN не решает проблему утечки, потому что браузер всё равно отправляет все ICE-кандидаты на сигнальный сервер. TURN нужен только для обхода симметричного NAT.

Реальный пример: как это выглядит на практике

Настраиваешь OpenVPN на VPS в Нидерландах. Проверяешь IP через 2ip.ru — всё чисто, виден амстердамский адрес. Открываешь сайт с WebRTC-утечкой — и вот он, твой домашний IP, в списке кандидатов.

Я проверил это на связке: Firefox 121, OpenVPN 2.6, VPS в Германии. Результат:

| Интерфейс | IP | Тип кандидата |

|-----------|-----|---------------|

| eth0 (VPN) | 10.8.0.2 | host |

| wlan0 (локальная сеть) | 192.168.1.37 | host |

| VPN-сервер | 185.243.18.77 | srflx |

| Реальный IP | 92.50.12.8 | srflx |

Последний кандидат появился потому, что VPN-клиент был настроен на split tunneling — локальный трафик шёл мимо туннеля. Браузер увидел этот маршрут и добавил кандидата.

Как проверить утечку самостоятельно

Не доверяй сайтам сомнительного качества. Используй простой скрипт. Открой консоль браузера (F12) и выполни:

```javascript

const pc = new RTCPeerConnection({

iceServers: [{ urls: "stun:stun.l.google.com:19302" }]

});

pc.createDataChannel("test");

pc.onicecandidate = (e) => {

if (e.candidate) {

console.log(e.candidate.candidate);

}

};

pc.createOffer().then((offer) => pc.setLocalDescription(offer));

```

Через несколько секунд в консоли появятся все ICE-кандидаты. Ищи строки с `typ host` — это локальные адреса. Если среди них есть твой реальный IP из подсети провайдера — утечка.

Для автоматической проверки можно использовать Python:

```python

import asyncio

import json

import websockets

async def check_webrtc():

async with websockets.connect("wss://webrtc.org/signaling") as ws:

await ws.send(json.dumps({"type": "offer", "sdp": "...your_sdp..."}))

response = await ws.recv()

data = json.loads(response)

if "candidate" in data:

print(data["candidate"]["candidate"])

asyncio.run(check_webrtc())

```

Но проще — написать страницу с JavaScript и открыть её локально. Браузер сам соберёт кандидатов.

Почему VPN-расширения не спасают

Расширения для браузера работают на уровне API. Они могут блокировать WebRTC или подменять IP в заголовках. Но WebRTC использует не HTTP-заголовки, а UDP-сокеты. Расширение не может перехватить трафик на уровне ядра.

Есть расширения, которые отключают WebRTC полностью. Это решает проблему утечки, но ломает видеозвонки, онлайн-конференции и некоторые мессенджеры. Обычно это приемлемо, но не всегда.

Некоторые расширения пытаются подменить ICE-кандидаты. Это работает только если сайт не проверяет их подлинность. Современные сервисы (Google Meet, Zoom) проверяют кандидаты через STUN. Подмена не прокатывает.

Настройка Firefox против утечек

Firefox даёт тонкую настройку. Заходим в `about:config`:

- `media.peerconnection.enabled` — `false` отключает WebRTC полностью

- `media.peerconnection.ice.default_addresses` — можно задать IP, который будет использоваться как адрес по умолчанию

- `media.peerconnection.ice.obfuscate_host_addresses` — `true` маскирует локальные IP в кандидатах

Последняя настройка заменяет реальные IP на случайные MD5-хеши. Собеседник увидит что-то вроде `a8f2c1d3e4b5...`. Но это не работает, если сайт использует mDNS-резолвинг.

Для полной блокировки лучше использовать uBlock Origin с включённым фильтром "Block WebRTC". Фильтр работает на уровне content script, блокирует вызовы `RTCPeerConnection`.

Прокси и VPN: правильная архитектура

Если тебе нужен и прокси, и WebRTC, придётся строить схему из двух уровней. Первый уровень — VPN-туннель, который заворачивает весь трафик. Второй — прокси для HTTP. WebRTC будет работать через VPN, но ICE-кандидаты будут содержать IP VPN-сервера.

Проблема в том, что браузер собирает кандидаты со всех интерфейсов. Даже если VPN работает, в системе может быть активен Wi-Fi адаптер с доступом к интернету. Браузер увидит его и добавит кандидата.

Решение — отключить все лишние сетевые интерфейсы при работе через VPN. Или настроить VPN так, чтобы он блокировал трафик вне туннеля. В OpenVPN это делается через `redirect-gateway def1` и `block-outside-dns`.

Кейс: сервер на nginx и WebRTC-утечка

Пример: сервер на nginx 1.24, раздающий статику и WebRTC-сигналинг. Логи показали, что клиенты подключаются с IP, которые не совпадают с IP в HTTP-запросах. Причина — браузер отправлял ICE-кандидаты с реальным IP, а HTTP-запросы шли через прокси.

Проблема решилась на стороне клиента: добавили в nginx конфиг заголовок, который информирует клиента о необходимости блокировки WebRTC:

```nginx

location /webrtc {

add_header X-WebRTC-Block "1" always;

proxy_pass http://backend;

proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;

}

```

Но это не техническое решение, а костыль. Клиент должен сам обработать заголовок и отключить WebRTC.

Кейс: корпоративная сеть с жёстким NAT

В корпоративной сети с симметричным NAT WebRTC не работает без TURN-сервера. Администраторы настроили coturn. Проблема: coturn логировал реальные IP клиентов, потому что браузер отправлял их в ICE-кандидатах. Это нарушало политику конфиденциальности.

Решение — настроить coturn на принудительное использование TURN и игнорирование host-кандидатов:

```bash

/etc/turnserver.conf

listening-port=3478

tls-listening-port=5349

realm=corp.example.com

server-name=corp.example.com

fingerprint

lt-cred-mech

user=webrtc:strongpassword

no-multicast-peers

no-cli

```

А на клиенте — в коде приложения указать, что используются только relay-кандидаты:

```javascript

const pc = new RTCPeerConnection({

iceServers: [{ urls: "turn:corp.example.com:3478", username: "webrtc", credential: "strongpassword" }],

iceTransportPolicy: "relay"

});

```

Это заставит браузер использовать только TURN-кандидаты. Реальные IP не покинут машину.

Кейс: браузерный торрент-клиент

WebTorrent использует WebRTC для передачи файлов. Пользователь включил VPN, но торренты продолжали светить реальный IP. Причина — WebTorrent собирает ICE-кандидаты со всех интерфейсов, включая тот, что не идёт через VPN.

Проблема усугублялась тем, что WebTorrent использует µTP поверх UDP. VPN-клиент не всегда корректно обрабатывает этот протокол. В итоге часть трафика шла мимо туннеля.

Решение — настройка VPN с kill-switch. В WireGuard это делается через `AllowedIPs = 0.0.0.0/0` и `Table = off` с дополнительными правилами iptables:

```bash

iptables -A OUTPUT -o wg0 -j ACCEPT

iptables -A OUTPUT -o eth0 -p udp --dport 51820 -j ACCEPT

iptables -A OUTPUT -o eth0 -j DROP

```

Это блокирует любой трафик, который не идёт через VPN-интерфейс. Браузер не сможет отправить ICE-кандидаты через Wi-Fi адаптер, потому что пакеты будут отброшены.

Заключение

WebRTC — это дыра в приватности. Браузер собирает все IP и отправляет их наружу. VPN и прокси не спасают, если не настроены правильно. Единственный надёжный способ — kill-switch на уровне ядра или полное отключение WebRTC.

Проверяй свои настройки. Не доверяй сайтам, которые обещают скрыть IP. Тестируй через консоль браузера. И помни: если в системе есть хоть один активный сетевой интерфейс, который не идёт через VPN, — твой IP утечёт.

✔️Купить прокси