WebRTC leak: как браузер выдаёт реальный IP поверх VPN и как это закрыть

Почему VPN не защищает от WebRTC-утечки​


VPN-туннель перехватывает трафик на сетевом уровне: все пакеты, идущие через интерфейс wg0 или tun0, шифруются и уходят через сервер провайдера. Но браузер способен устанавливать соединения в обход системной таблицы маршрутизации — через API, которые работают на уровне приложения.

WebRTC (Web Real-Time Communication) — набор JavaScript API для организации голосовой и видеосвязи, передачи данных между браузерами без промежуточных серверов. Для установки прямого P2P-соединения браузеру необходимо узнать собственные сетевые адреса — в том числе локальные и публичные. Этот процесс называется ICE (Interactive Connectivity Establishment) candidate gathering.

Ключевой момент: при сборе ICE-кандидатов браузер обращается к сетевому стеку напрямую, минуя VPN-туннель. Если в системе доступен реальный сетевой интерфейс с публичным IP, браузер включит его в список кандидатов и передаст удалённой стороне через STUN/TURN-запросы или непосредственно в SDP-оффер.

Механика утечки​


Процесс выглядит так:

  1. JavaScript на странице создаёт объект RTCPeerConnection.
  2. Браузер начинает сбор ICE-кандидатов: перебирает все доступные сетевые интерфейсы.
  3. Для каждого интерфейса формируется кандидат типа host (локальный адрес), srflx (адрес, видимый STUN-сервером) или relay (адрес TURN-сервера).
  4. Кандидаты передаются удалённой стороне через signaling-канал.
  5. Любой сервер или скрипт, участвующий в signaling, получает реальный IP.

Утечка возможна даже если:

  • VPN-клиент активен и маршрутизация настроена корректно.
  • DNS-запросы идут через туннель.
  • Браузер настроен на использование прокси.

Причина: WebRTC не использует системный прокси и не привязан к VPN-интерфейсу. Он работает с сокетами напрямую.

Как проверить утечку​


Быстрая проверка через онлайн-сервисы​


Подключите VPN, откройте один из сервисов проверки:


Если в результатах виден ваш реальный публичный IP (отличающийся от IP VPN-сервера) — утечка подтверждена.

Проверка через консоль браузера​


Откройте DevTools (F12) → Console и выполните:

JavaScript:
const pc = new RTCPeerConnection({iceServers: []});
pc.createDataChannel('');
pc.createOffer().then(offer => pc.setLocalDescription(offer));
pc.onicecandidate = (e) => {
  if (e.candidate) {
    console.log(e.candidate.candidate);
  }
};

В выводе появятся строки вида:

Код:
candidate:1 1 udp 2122260223 192.168.1.42 54321 typ host

Если среди кандидатов виден ваш реальный публичный IP — утечка есть.

Проверка через Wireshark​


Запустите захват на физическом интерфейсе (не на VPN-интерфейсе):

Bash:
sudo tcpdump -i eth0 -n 'udp port 3478 or udp port 5349'

Порты 3478 и 5349 — стандартные для STUN/TURN. Если при активном VPN на физическом интерфейсе видны такие пакеты, браузер отправляет STUN-запросы в обход туннеля.

Способы закрытия утечки​


Firefox: полное отключение WebRTC​


Firefox позволяет полностью отключить WebRTC через about:config:

  1. Откройте about:config.
  2. Найдите параметр media.peerconnection.enabled.
  3. Установите значение false.

После этого RTCPeerConnection станет недоступен, и утечка через WebRTC исключена. Побочный эффект: перестанут работать видеозвонки в мессенджерах, использующих WebRTC (например, некоторые режимы Discord, Jitsi).

Дополнительно можно ограничить типы кандидатов:

  • media.peerconnection.ice.default_address_only = true — браузер будет использовать только адрес по умолчанию (тот, что назначен системной маршрутизацией, то есть VPN-адрес).
  • media.peerconnection.ice.no_host = true — исключает кандидатов типа host (локальные адреса).

Chrome и Chromium-браузеры​


Chrome не предоставляет встроенного флага для полного отключения WebRTC. Доступные варианты:

Расширения. Расширения вроде uBlock Origin или специализированные (например, WebRTC Network Limiter) могут ограничить поведение, но не гарантируют полную блокировку на уровне движка.

Флаг командной строки. Запуск с флагом --disable-features=WebRtcHideLocalIpsWithMdns не отключает WebRTC, а лишь скрывает локальные адреса за mDNS-псевдонимами. Публичный IP всё равно может утечь через srflx-кандидаты.

Полное решение для Chrome — маршрутизация всего трафика через VPN на уровне системы, включая UDP. Если VPN-клиент настроен с AllowedIPs = 0.0.0.0/0 (как в WireGuard-конфигурации клиента), весь исходящий трафик, включая STUN-запросы браузера, пойдёт через туннель.

WireGuard: маршрутизация всего трафика​


Если используется WireGuard, клиентская конфигурация с AllowedIPs = 0.0.0.0/0 направляет весь трафик — включая UDP-пакеты STUN — через туннель. В этом случае даже если браузер формирует ICE-кандидаты, они будут содержать IP, назначенный VPN-интерфейсом, а не реальный публичный адрес.

Пример клиентской конфигурации:

INI:
[Interface]
PrivateKey = <ваш_приватный_ключ>
Address = 10.8.0.2/32

[Peer]
PublicKey = <публичный_ключ_сервера>
Endpoint = 203.0.113.1:51820
AllowedIPs = 0.0.0.0/0

Здесь AllowedIPs = 0.0.0.0/0 означает, что все пакеты (любой адрес назначения) шифруются и отправляются через туннель. STUN-запросы браузера не смогут уйти через физический интерфейс.

Важное ограничение: если VPN-клиент не перехватывает UDP-трафик или настроен на раздельное туннелирование (split tunneling), WebRTC-пакеты могут обойти туннель.

Сетевой уровень: блокировка STUN/TURN на интерфейсе​


Если по какой-то причине VPN не покрывает весь трафик, можно заблокировать исходящие STUN/TURN-запросы на физическом интерфейсе:

Bash:
sudo iptables -A OUTPUT -o eth0 -p udp --dport 3478 -j DROP
sudo iptables -A OUTPUT -o eth0 -p udp --dport 5349 -j DROP

Это предотвратит утечку через srflx-кандидаты, но сломает WebRTC-связь полностью. Кандидаты типа host (локальные адреса) при этом всё равно могут быть видны скриптам на странице.

Отключение WebRTC на уровне ОС (радикальный метод)​


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

Типичные ошибки при защите​


ОшибкаПочему не работает
Включён только HTTP-прокси в браузереWebRTC игнорирует прокси и работает с сокетами напрямую
VPN настроен только на TCPSTUN/TURN используют UDP; без перехвата UDP утечка сохраняется
Split tunneling с исключением браузераБраузерный трафик идёт напрямую, минуя туннель
Отключён только host-кандидатsrflx-кандидат всё равно раскрывает публичный IP через STUN
Расширение «WebRTC Leak Prevent» без проверкиРасширения не всегда перехватывают все пути утечки; необходима повторная проверка

Проверка после применения мер​


После настройки выполните повторную проверку:

  1. Перезапустите браузер полностью (не просто закройте вкладку).
  2. Подключите VPN.
  3. Откройте WebRTC Leak Test.
  4. Убедитесь, что в списке кандидатов нет реального IP.
  5. Дополнительно выполните скрипт из консоли DevTools и проверьте вывод.

Если в кандидатах виден только IP из подсети VPN (например, 10.8.0.2) или адреса не появляются вовсе — утечка закрыта.

Ограничения и компромиссы​


  • Полное отключение WebRTC ломает видеозвонки, P2P-передачу файлов и некоторые стриминговые сервисы.
  • Блокировка STUN/TURN на уровне файрвола может повлиять на другие приложения, использующие эти протоколы (некоторые VoIP-клиенты, игры).
  • В Chrome без маршрутизации всего трафика через туннель гарантировать отсутствие утечки невозможно на уровне браузера.
  • Некоторые сайты детектируют отключённый WebRTC и могут ограничивать функциональность.

Для большинства сценариев оптимальная комбинация: полнопрофильный VPN с перехватом всего трафика (включая UDP) + media.peerconnection.enabled = false в Firefox как дополнительная страховка.

Источники​


 
Назад
Верх Низ