WebRTC утечка: как проверить и отключить показ реального адреса
WebRTC способен показать площадке настоящий адрес машины даже при исправно работающем прокси, потому что собирает сетевые кандидаты своими средствами и обращается к серверам STUN напрямую по UDP. Проверяется это маленькой страницей на javascript, которая выводит перечень кандидатов, а закрывается настройкой браузера: в Firefox переключателем в about:config, в браузерах на Chromium политикой или расширением, в антидетект-браузерах полем в карточке профиля.
Разбираем по порядку: зачем браузеру эта технология, как устроен сбор кандидатов, что читается в их перечне, как собрать проверочную страницу за десять строк, какие настройки закрывают вопрос в каждом браузере и почему пустой перечень кандидатов сам по себе тоже выглядит приметно.
Зачем браузеру WebRTC и откуда берётся показ адреса
WebRTC отвечает за прямую связь между браузерами: видеозвонки, голос, обмен файлами, демонстрация экрана, игровые каналы. Прелесть технологии в том, что данные идут напрямую между участниками, без пересылки через сервер посередине. Задержка падает, канал держится, качество картинки растёт.
Прямая связь требует знания адресов. Браузеру нужно понять, по каким маршрутам до него можно достучаться: адрес внутри локальной сети, адрес на внешней стороне домашнего или офисного маршрутизатора, адрес через ретранслятор. Этот перечень маршрутов и называется кандидатами.
Главное тут в том, как кандидаты собираются. Сбор идёт на уровне сетевого стека браузера, ниже слоя обычных HTTP-запросов, и настройка прокси в браузере на него исторически не влияла. Обращения к серверу STUN уходят по UDP на порт 3478, посредник по TCP их не видит и не может перенаправить. Браузер добросовестно узнаёт свой внешний адрес и складывает его в перечень.
Дальше страница читает перечень обычным скриптом. Никаких особых разрешений для этого не нужно: объект RTCPeerConnection создаётся из javascript, кандидаты приходят событиями, и площадка получает список маршрутов без единого вопроса пользователю. Отсюда и родилась вся история с проверками, расширениями и настройками профилей.
Мы разбираем этот сценарий отдельно, потому что он ломает картину незаметно. Все прочие проверки говорят, что доступ работает: выходной адрес из пула, заголовки ровные, коды ответов рабочие. А страница тем временем получила пару адресов, к прокси отношения не имеющих.
Как собираются кандидаты: STUN, UDP и обход посредника
Механика короткая. Браузер создаёт соединение, получает от страницы адреса серверов STUN и начинает опрос. Локальные сетевые интерфейсы он перечисляет сам, читая адреса с сетевых карт. Внешний адрес узнаёт у сервера STUN: отправляет пакет и получает ответ, в котором сервер пишет, с какого адреса и порта этот пакет пришёл.
# запрос к серверу STUN уходит по UDP и минует TCP-посредника
stun.l.google.com:19302
stun1.l.google.com:19302
Опрос идёт по всем доступным интерфейсам. Проводная карта, беспроводная карта, виртуальный адаптер гипервизора, туннельный интерфейс: каждый даёт свой кандидат. Поэтому на рабочей станции с виртуальными машинами перечень получается длинным и рассказывает о конфигурации больше, чем хотелось бы.
Браузеры на Chromium с некоторого времени прячут локальные адреса за случайными именами вида a1b2c3d4-....local. Приём называется mDNS-обфускацией и закрывает адреса внутренней сети. Внешний адрес от сервера STUN он не трогает, поэтому основной вопрос остаётся открытым.
Отдельно про порядок сборки. Кандидаты приходят по одному, событиями onicecandidate, и последним прилетает пустое событие, означающее конец перечня. Страница может собрать всё за долю секунды и отправить на свой сервер до того, как пользователь заметит хоть что-то. Проверка поэтому делается заранее, до первого захода на целевую площадку.
Работу через посредника здесь спасает согласованность настроек в браузерном профиле. Именно поэтому вопрос закрывают на стороне профиля, а связку с адресами из пула удобно смотреть на странице про прокси для антидетект-браузеров.
Перечень кандидатов: что в нём читается
Кандидат приходит строкой заданного формата. Выглядит она так:
candidate:842163049 1 udp 1677729535 93.184.216.34 54321 typ srflx
raddr 0.0.0.0 rport 0 generation 0 ufrag k7Qm network-cost 999
Разбирается строка слева направо: идентификатор, номер компонента, транспорт, приоритет, адрес, порт, тип. Тип это самое ценное поле, и типов всего четыре.
| Тип кандидата | Откуда берётся | Что показывает площадке | Опасность при работе через прокси |
|---|---|---|---|
host | сетевые карты машины | адрес внутри локальной сети, вид сетевой конфигурации | средняя, в Chromium скрыт за .local |
srflx | ответ сервера STUN | внешний адрес канала машины | высокая, это и есть открытие настоящего адреса |
prflx | ответ второй стороны соединения | внешний адрес, добытый в обход STUN | высокая, возникает при активном звонке |
relay | сервер TURN | адрес ретранслятора | низкая, настоящий адрес прикрыт |
Кроме типа читается ещё несколько вещей. Поле network-cost намекает на характер интерфейса, число интерфейсов говорит о наличии виртуальных машин и туннелей, диапазон портов иногда выдаёт версию сетевого стека. Проверяющий скрипт площадки складывает это с прочими признаками и получает отдельную характеристику браузера.
Самое неприятное сочетание такое: выходной адрес из пула в заголовках соединения и srflx с адресом домашнего канала в кандидатах. Расхождение видно мгновенно, разбирать его не требуется. Поэтому проверку кандидатов мы ставим в один ряд с проверкой заголовков и с разбором того, что сайт видит о вас через прокси.
Проверочная страница на javascript
Готовые сервисы проверки удобны, но собственная страница честнее: она лежит у вас, ничего не отправляет наружу и работает даже без сети. Кода в ней десяток строк.
<pre id="out">сбор кандидатов...</pre>
<script>
const out = document.getElementById('out');
const rows = [];
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
pc.createDataChannel('probe');
pc.onicecandidate = e => {
if (!e.candidate) { out.textContent = rows.join('\n') || 'кандидатов нет'; return; }
const c = e.candidate.candidate;
const m = c.match(/candidate:\S+ \d+ (\S+) \d+ (\S+) (\d+) typ (\S+)/);
rows.push(m ? `${m[4].padEnd(6)} ${m[1]} ${m[2]}:${m[3]}` : c);
out.textContent = rows.join('\n');
};
pc.createOffer().then(o => pc.setLocalDescription(o));
</script>
Файл сохраняется как webrtc-probe.html и открывается в проверяемом браузере. Через секунду в окне появится перечень кандидатов с типом в первой колонке. Читать его просто: строки с srflx содержат внешний адрес, и он должен совпадать с выходным адресом прокси либо отсутствовать совсем.
Ту же страницу удобно держать внутри антидетект-браузера, в профиле, где идёт работа. Мы кладём её локальным файлом и открываем сразу после создания профиля, до первого захода на площадку. Занимает это секунд двадцать.
Для сверки рядом открывается обычный эхо-сервис, который показывает адрес соединения:
curl -x http://user5521:[email protected]:8000 https://ifconfig.me
Совпадение двух цифр означает согласованную настройку. Расхождение означает, что сбор кандидатов идёт мимо посредника и требует правки в настройках браузера.
Firefox: отключение через about:config
Firefox даёт самый прямой доступ к настройке. Открываем about:config, соглашаемся с предупреждением и правим параметры.
media.peerconnection.enabled = false
media.peerconnection.ice.default_address_only = true
media.peerconnection.ice.no_host = true
media.peerconnection.ice.proxy_only_if_behind_proxy = true
Первый параметр выключает технологию целиком: объект RTCPeerConnection перестаёт создаваться, и проверочная страница напишет про ошибку. Три остальных работают мягче. default_address_only оставляет один кандидат по умолчанию, no_host убирает кандидаты с локальных интерфейсов, proxy_only_if_behind_proxy заставляет весь трафик технологии идти через настроенный прокси при его наличии.
Для повседневной работы удобнее мягкий набор без полного выключения. Видеозвонки при этом остаются рабочими, а перечень кандидатов ужимается до одной строки с адресом посредника. Полное выключение берут там, где браузер занят прогонами и звонки в нём не нужны.
Параметры переживают перезапуск браузера, но сбрасываются при создании нового профиля и иногда после крупных обновлений. Поэтому проверочная страница открывается заново после каждого обновления.
Отдельно про network.proxy.socks_remote_dns. Он к кандидатам отношения не имеет, зато закрывает соседний канал раскрытия, и включать его стоит в том же заходе. Подробности собраны в материале про утечку запросов к DNS.
Браузеры на Chromium: политика и расширение
В Chrome, Edge, Brave и прочих сборках на Chromium доступа к внутренним параметрам через интерфейс нет: флаг из chrome://flags убрали, а поле в настройках не завезли. Работают два пути.
Первый путь это политика браузера. Параметр WebRtcIPHandling принимает четыре значения и задаётся в реестре на Windows либо файлом политики на Linux и macOS.
# Windows, ветка реестра
HKLM\SOFTWARE\Policies\Google\Chrome
WebRtcIPHandling = "disable_non_proxied_udp"
# Linux, файл /etc/opt/chrome/policies/managed/webrtc.json
{
"WebRtcIPHandling": "disable_non_proxied_udp",
"WebRtcLocalIpsAllowedUrls": []
}
Значение disable_non_proxied_udp запрещает UDP-трафик технологии мимо посредника: при настроенном прокси кандидаты собираются через него, при отсутствии прокси соединение просто не устанавливается. Значение default_public_interface_only оставляет один внешний интерфейс, default_public_and_private_interfaces добавляет к нему локальные адреса. Политика применяется после перезапуска браузера и проверяется на странице chrome://policy.
Второй путь это расширение. В магазине есть несколько расширений, которые дёргают тот же внутренний параметр через chrome.privacy.network.webRTCIPHandlingPolicy. Работают они предсказуемо, ставятся за минуту и подходят там, где до реестра нет доступа. Одно замечание: расширение видно на странице списка расширений, и оно само по себе становится частью отпечатка браузера.
| Браузер | Способ закрытия | Что меняется | Видно ли изменение снаружи |
|---|---|---|---|
| Firefox | параметры в about:config | кандидаты сокращаются до одного или исчезают | при полном выключении объект недоступен |
| Chrome и Edge | политика WebRtcIPHandling | UDP мимо посредника запрещён | перечень кандидатов пустой либо один srflx |
| Brave | штатный переключатель в настройках | режим обработки адресов | так же, как в Chrome |
| Любой Chromium | расширение из магазина | тот же внутренний параметр | расширение видно в списке установленных |
| Антидетект-браузер | поле в карточке профиля | адрес в кандидатах подменяется на адрес прокси | перечень выглядит согласованно |
| Контейнер без графики | технология отсутствует | кандидатов нет вовсе | площадка видит браузер без поддержки |
Антидетект-браузеры: вопрос закрывается настройкой профиля
Здесь механика устроена иначе, и это главное отличие. Обычный браузер умеет только выключить сбор кандидатов или ограничить его. Антидетект-браузер умеет подставить в кандидаты нужные значения: он берёт выходной адрес прокси из карточки профиля и отдаёт странице кандидат srflx именно с ним.
В карточке профиля поле обычно называется «WebRTC» и принимает три состояния. «Отключён» убирает технологию целиком. «Реальный» отдаёт настоящие адреса машины. «Подменённый» или «на основе прокси» подставляет адрес из поля прокси того же профиля. Рабочее состояние для задач с несколькими кабинетами это третье.
Смысл именно в согласованности. Профиль хранит весь набор сразу: выходной адрес, отпечаток холста, часовой пояс, язык интерфейса, разрешение экрана, набор шрифтов и режим WebRTC. Все поля берутся из одного набора и не спорят друг с другом. Мы держим этот принцип базовым: адрес из пула, часовой пояс под адрес, кандидаты под адрес.
Проверка профиля делается той же локальной страницей. Открыли профиль, открыли файл, посмотрели на строку srflx, сверили с выходным адресом. Совпало значит готово. В Dolphin Anty, Octo Browser, AdsPower и Undetectable поле называется по-разному, логика одна.
Мы обычно заводим один эталонный профиль и дальше клонируем его под задачи. В эталоне заранее выставлены режим WebRTC, часовой пояс, язык и поле прокси, поэтому копия рождается согласованной и требует замены одной строки подключения. Такой порядок экономит время на серии из десятка профилей и снимает самую частую ошибку, когда новый профиль наследует режим «Реальный» от шаблона по умолчанию. Что именно принимает каждое поле и в каком виде туда кладётся строка, разобрано на странице про антидетект-браузеры и работу с профилями.
Отдельно про источник адресов. Подмена работает корректно тогда, когда прокси в профиле живой и отдаёт стабильный выход на время сессии. Под такую работу берут приватный доступ к пулу адресов с привязкой рабочей машины, а строку подключения кладут в поле профиля целиком. Про связку с конкретной программой есть отдельный разбор на странице про настройку Dolphin Anty с прокси.
Почему выключенный WebRTC тоже заметен
Полное выключение технологии закрывает адрес и создаёт другой признак. Доля браузеров без поддержки WebRTC в живом трафике мала, и проверяющий скрипт эту долю знает. Браузер последней версии на настольной системе, который отвечает отказом на создание RTCPeerConnection, выглядит настроенным вручную.
Так же читается пустой перечень кандидатов при работающем объекте. Объект создался, событие конца перечня пришло, кандидатов ноль. Штатная машина такого не показывает почти никогда.
Согласованная настройка выглядит иначе. Технология доступна, объект создаётся, кандидаты приходят, и в них стоит внешний адрес, совпадающий с адресом соединения. Локальные адреса при этом либо скрыты за .local, либо отсутствуют, что для Chromium вполне обычное состояние. Такой перечень ничем не выделяется среди обычного трафика.
| Состояние браузера | Что видит проверяющий скрипт | Насколько обычно выглядит |
|---|---|---|
| Технология выключена целиком | ошибка при создании объекта | приметно на настольной системе |
| Объект есть, кандидатов ноль | пустой перечень до события конца | приметно |
| Кандидаты с адресом машины | srflx спорит с адресом соединения | сразу читаемое расхождение |
| Кандидаты с адресом прокси | srflx совпадает с адресом соединения | обычная картина |
Только relay через TURN | адрес ретранслятора | обычная картина за корпоративной сетью |
Отсюда рабочий порядок. Для разовых проверок и прогонов, где браузер отвечает только за загрузку страниц, полное выключение подходит. Для работы с несколькими кабинетами берётся подмена на адрес прокси, потому что там браузер должен выглядеть обычным на длинной дистанции.
Мы держим оба режима под рукой и выбираем по характеру задачи. Разовый съём страницы через скрипт с браузерным движком получает выключенную технологию: кандидаты там никому не нужны, и лишний сетевой обмен только замедляет прогон. Долгая работа в кабинете получает подмену, потому что площадка смотрит на профиль неделями и накапливает статистику по каждому признаку. Смешивать режимы внутри одного набора профилей смысла мало: половина выглядит одним образом, половина другим, и разнородность сама становится приметой.
Что проверять после изменений
Первое: перечень кандидатов на локальной странице. Смотрим тип каждой строки и адрес в строках srflx. Второе: выходной адрес соединения через эхо-сервис в том же окне. Третье: сверка двух цифр между собой. Четвёртое: часовой пояс и язык браузера, потому что они читаются тем же скриптом и должны соответствовать общей картине.
Проверять стоит после каждого обновления браузера, после создания нового профиля и после смены пакета прокси. Обновления возвращают часть параметров к значениям по умолчанию, а новый профиль наследует настройки шаблона, который мог остаться от прежней задачи.
Мы держим проверочную страницу в закладках каждого рабочего профиля, рядом с эхо-сервисом. Две вкладки, один взгляд, десять секунд. Такой порядок дешевле разбора последствий: профиль, отработавший неделю с настоящим адресом в кандидатах, уже накопил историю, и переделывать её задним числом бессмысленно. Смотрим сразу, до первого захода на площадку.
# быстрая сверка адреса соединения из консоли
curl -s -x http://user5521:[email protected]:8000 https://ifconfig.me
curl -s -x http://user5521:[email protected]:8000 https://api.ipify.org
Два независимых эхо-сервиса берутся намеренно: один может отдать кэшированный ответ. Совпадение обоих с адресом в кандидатах закрывает вопрос.
Всю серию удобно пройти на бесплатном тесте до 2 часов. Пакет включается примерно за 5 минут, список приходит в форматах IP:PORT и IP:PORT:LOGIN:PASS ссылкой или файлом, дальше идёт настройка профиля и проверка кандидатов. Двух часов хватает на несколько профилей подряд. Под браузерные профили обычно берут адреса SOCKS5 для работы в браузере, они принимаются полем прокси во всех перечисленных программах.
Частые вопросы
Какой тип прокси ставить в профиль антидетект-браузера?
В пакете IPv4 доступны SOCKS4 и SOCKS5 на выбор, рекомендуется SOCKS5. Он принимает доменные имена, работает с авторизацией по логину и паролю и поддерживается полем прокси во всех известных антидетект-браузерах. Подмена адреса в кандидатах при этом опирается на тот адрес, который стоит в карточке профиля, поэтому строка подключения вписывается целиком.
Подойдут ли прокси под работу с браузерными профилями?
Заранее предугадать поведение каждой площадки нельзя, поэтому перед покупкой доступен бесплатный тест до 2 часов под ваш запрос. Порядок запуска короткий: выбрать тип прокси под свой софт, зарегистрироваться в кабинете, отправить запрос теста из меню, указать свой адрес в настройках, активировать доступ и написать оператору логин и тип прокси. Проверка кандидатов на своей странице как раз укладывается в тестовое окно.
Почему в кандидатах адрес каждый раз другой?
Пул держится в районе 12 000 активных адресов, ротация идёт автоматически внутри пула, список обновляется в реальном времени. Смена выходного адреса между сессиями это штатная работа сервиса. Если под задачу нужна одинаковая точка выхода на всю сессию, соединение держится открытым, и адрес в кандидатах остаётся прежним до его завершения. Подробности про режимы работы смотрите там, где описан анонимный доступ через общий пул.
Сколько профилей можно вести на одном пакете?
Ограничений на число пакетов у аккаунта нет, а внутри пакета работа идёт по числу потоков: стандартные пакеты дают до 1000 потоков, корпоративный до 3000. При двух привязанных адресах общий лимит делится пополам, и пакеты по потокам не складываются. Один браузерный профиль занимает несколько соединений, поэтому даже стандартный пакет закрывает десятки профилей одновременно.
Дальше по разделу диагностики собраны соседние разборы: базовая проверка доступа командами и браузером описана в материале про то, как убедиться, что прокси работает, разбор уходящих заголовков лежит в проверке анонимности прокси, а замер задержки без искажений разобран в заметке про скорость и время отклика. Прикладную сторону работы с профилями и площадками смотрите в материале про соцсети и отложенный постинг.