Почему 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-оффер.
Механика утечки
Процесс выглядит так:
- JavaScript на странице создаёт объект
RTCPeerConnection.
- Браузер начинает сбор ICE-кандидатов: перебирает все доступные сетевые интерфейсы.
- Для каждого интерфейса формируется кандидат типа
host(локальный адрес),srflx(адрес, видимый STUN-сервером) илиrelay(адрес TURN-сервера).
- Кандидаты передаются удалённой стороне через signaling-канал.
- Любой сервер или скрипт, участвующий в 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:- Откройте
about:config.
- Найдите параметр
media.peerconnection.enabled.
- Установите значение
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 настроен только на TCP | STUN/TURN используют UDP; без перехвата UDP утечка сохраняется |
| Split tunneling с исключением браузера | Браузерный трафик идёт напрямую, минуя туннель |
Отключён только host-кандидат | srflx-кандидат всё равно раскрывает публичный IP через STUN |
| Расширение «WebRTC Leak Prevent» без проверки | Расширения не всегда перехватывают все пути утечки; необходима повторная проверка |
Проверка после применения мер
После настройки выполните повторную проверку:
- Перезапустите браузер полностью (не просто закройте вкладку).
- Подключите VPN.
- Откройте WebRTC Leak Test.
- Убедитесь, что в списке кандидатов нет реального IP.
- Дополнительно выполните скрипт из консоли DevTools и проверьте вывод.
Если в кандидатах виден только IP из подсети VPN (например,
10.8.0.2) или адреса не появляются вовсе — утечка закрыта.Ограничения и компромиссы
- Полное отключение WebRTC ломает видеозвонки, P2P-передачу файлов и некоторые стриминговые сервисы.
- Блокировка STUN/TURN на уровне файрвола может повлиять на другие приложения, использующие эти протоколы (некоторые VoIP-клиенты, игры).
- В Chrome без маршрутизации всего трафика через туннель гарантировать отсутствие утечки невозможно на уровне браузера.
- Некоторые сайты детектируют отключённый WebRTC и могут ограничивать функциональность.
Для большинства сценариев оптимальная комбинация: полнопрофильный VPN с перехватом всего трафика (включая UDP) +
media.peerconnection.enabled = false в Firefox как дополнительная страховка.
