Защита от сканирования портов браузером на localhost
Как веб-страница может опрашивать порты localhost, чтобы узнать, какие локальные службы вы запускаете, почему обычные меры не помогают и как проверить единообразное поведение.
BotBrowser Team
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
Веб-страница может попросить браузер открыть соединение с адресом на вашем собственном компьютере, и браузер обычно попробует это сделать. Если на этом порту работает служба, попытка завершится успешно или вернётся ответ на уровне протокола. Если никто не слушает, попытка будет отклонена. Страница, которая повторяет попытку для набора известных портов, получает картину открытых и закрытых портов, а эта картина многое говорит о программах, которыми вы пользуетесь.
Разделы ниже прослеживают этот вывод от одной попытки соединения до устойчивого признака локального окружения, сравнивают распространённые обходные пути и пробел, который остаётся у каждого из них, а затем переходят к защите портов BotBrowser, которая делает ответы единообразными. В конце даны проверка, которую можно выполнить на своём компьютере, и прямое описание того, что эта функция не покрывает.
Кратко
Защита портов BotBrowser делает одинаковыми проверки страницами документированных петлевых портов, а прямые подключения локальных инструментов сохраняет. Она не охватывает все порты и адреса частной сети, поэтому перед включением нужно проверить точную форму адреса и набор портов.
Содержание
- Как страница составляет карту ваших локальных служб
- Почему эта картина следует за вами из сеанса в сеанс
- Почему обычные обходные пути не помогают
- Включение защиты портов
- Проверка единообразных результатов на локальной тестовой службе
- Что поддерживает BotBrowser и что остаётся за его пределами
- Итог
Как страница составляет карту ваших локальных служб
У каждого компьютера есть петлевой интерфейс, который нужен, чтобы программы на одном хосте могли общаться между собой, не выходя за его пределы. RFC 1122 резервирует для этого весь блок 127.0.0.0/8, а RFC 4291 определяет ::1 как петлевой адрес IPv6. Имя хоста localhost обычно разрешается в один из этих адресов или в оба. Службы, рассчитанные только на локального пользователя, например серверы разработки, СУБД, помощники удалённого рабочего стола и инструменты контейнеров, часто слушают именно там, потому что с других машин петлевой интерфейс недоступен.
Однако браузер работает на том же компьютере, поэтому код страницы может обращаться к тем же конечным точкам. Для этого на странице не нужно ничего устанавливать или подтверждать. Страница выполняет обычную попытку соединения, например через WebSocket, загрузку изображения или вызов fetch, а затем смотрит, чем эта попытка закончилась. Разные исходы сообщают странице разное:
- Служба, которая принимает соединение и отвечает узнаваемым образом, говорит о том, что на этом порту работает определённый вид программ.
- Служба, которая принимает соединение, но отвечает чем-то непонятным для страницы, всё равно показывает, что порт открыт.
- Отклонённое соединение показывает, что никто не слушает, и способ, которым приходит отказ, может отличаться от способа, которым завершается принятое соединение.
Ничего из этого не читает данные локальной службы. Страница узнаёт лишь, что порт ведёт себя так или иначе, но при достаточном числе портов это на удивление подробное описание компьютера. Страница, проверяющая несколько десятков известных портов, часто может определить, есть ли у посетителя среда веб-разработки, база данных, средство удалённого доступа или платформа контейнеров.
Это важно не только для отслеживания, потому что многие локальные службы пишутся в расчёте на то, что до них могут дотянуться только программы на том же компьютере. Они нередко обходятся без входа в систему, слушают известный порт и предоставляют простой HTTP-интерфейс. Страница, узнавшая о существовании такой службы, уже получила информацию, а страница, которая ещё и может отправлять ей запросы, может получить больше. Со временем браузеры ужесточили правила для запросов между источниками, но узнать, что порт открыт, намного проще, чем прочитать ответ. Поэтому защиты заслуживает именно сама картина открытых и закрытых портов.
Предложение Local Network Access от WICG описывает такой класс запросов, когда страница с публичного сайта обращается к локальным и петлевым адресам, и предлагает, чтобы браузеры закрывали такие запросы разрешением. Это спецификация сообщества, поддержка у браузеров и версий различается, поэтому не считайте, что ваш текущий браузер запрашивает разрешение или блокирует обращение. Прежде чем полагаться на неё, проверьте, что делает ваша собственная сборка.
Почему эта картина следует за вами из сеанса в сеанс
Сравните 127.0.0.1:3000 и 127.0.0.1:5432 в одном профиле: результат определяется процессами хоста, а не cookie.
Файлы cookie, локальное хранилище и IP-адрес можно очистить или сменить. Набор служб, работающих на вашем компьютере, устроен иначе, потому что он описывает, как вы работаете, а не откуда подключаетесь. Разработчик, который каждый день использует ту же интеграцию редактора, ту же базу данных и ту же среду контейнеров, в понедельник и в пятницу покажет одну и ту же картину.
Именно эта устойчивость делает признак полезным для отслеживания. Рассмотрите распространённые способы начать с чистого листа:
- Очистка cookie и данных сайтов удаляет состояние, которое сайт сохранил в браузере, но не меняет того, какие порты открыты.
- Смена IP-адреса, например через прокси, меняет сетевое расположение, которое видит сайт, но картина петлевых портов принадлежит компьютеру и путешествует вместе с ним.
- Приватное окно или второй профиль браузера сбрасывает состояние браузера, но тот же компьютер отвечает так же.
Этот признак к тому же хорошо сочетается с другими. Картина открытых и закрытых портов это ещё один атрибут, который можно объединить с результатом canvas, доступными шрифтами и остальной поверхностью, которую собирает скрипт снятия отпечатка. Каждый атрибут по отдельности даёт лишь часть картины, а вместе они могут выделить компьютер, поэтому стоит закрывать даже один слабый признак. О том, почему приватное окно не меняет эти признаки, читайте в статье Почему режим инкогнито не защищает от снятия отпечатков, где шаг за шагом сравниваются обычный и приватный сеансы.
Не все компьютеры одинаково заметны. Ноутбук, который используется только для почты и документов, может показывать почти ни одного открытого порта, и его картина близка к картине многих других машин. Рабочая станция или сервер с десятком служб гораздо заметнее. Больше всех выигрывают от обработки этого признака разработчики, операторы серверов без графического интерфейса и все, кто пользуется средствами удалённого доступа, поскольку такие конфигурации слушают больше портов, чем типичный домашний компьютер.
Почему обычные обходные пути не помогают
Даже touch-action: none меняет жесты касания, но не результат соединения с 127.0.0.1:3000.
Мгновенный ответ ERR_BLOCKED_BY_CLIENT также измерим; перед правилом сравните его с обычным тайм-аутом соединения.
Тестовая страница может вызвать fetch() с AbortSignal.timeout(1000) для http://127.0.0.1:3000/; наблюдаемыми поверхностями будут время и класс ошибки.
Несколько подходов выглядят разумно, и у каждого остаётся пробел.
Прямая блокировка петлевых соединений. Если браузер отклоняет любую попытку обратиться к localhost, страница больше не узнаёт, какая служба работает. Но сам отказ становится наблюдаемым поведением. Заблокированная попытка может выглядеть иначе, чем обычный отказ, а одинаковый мгновенный сбой на каждом порту необычен по сравнению с разбросом, который показывает обычный браузер. Блокировка также ломает то, на что вы можете рассчитывать: настольные приложения-компаньоны, которые общаются с веб-страницей, серверы разработки с живой перезагрузкой и сценарии входа, которые перенаправляют обратно на локальный приёмник.
Расширения браузера. Фильтры запросов могут блокировать соединения с локальными адресами, но они работают на уровне расширений браузера, и охват зависит от типа запроса. Правило, которое обрабатывает вызовы fetch, может не покрывать остальные способы, которыми страница открывает соединение. Само расширение тоже может оставлять следы, которые страница способна заметить, и тогда защита сама становится ещё одним отличительным признаком.
Правила брандмауэра. Брандмауэры операционной системы решают, каким программам можно принимать входящие соединения или выходить в сеть. Соединение с localhost, начатое страницей, это локальное соединение самого браузера, поэтому правило, настроенное под трафик из интернета, к нему неприменимо. Правило, которое не даёт браузеру обращаться к петлевому интерфейсу, снова сломает локальные инструменты, которые вы хотите сохранить, и вернёт проблему приметного отказа.
Сетевые пространства имён и контейнеры. Запуск браузера в контейнере с отдельным сетевым пространством имён не даёт ему видеть службы хоста, и это действительно разделяет их. Цена связана с эксплуатацией: вы поддерживаете лишний слой, вам трудно дотянуться до служб хоста, которые вы как раз хотите использовать, а сам контейнер показывает собственный набор слушающих служб, которые страница может опросить. Это разумный инструмент изоляции для некоторых развёртываний и слишком тяжёлый ответ на эту конкретную проблему.
Маршрутизация через VPN. VPN меняет путь исходящего интернет-трафика. Петлевой трафик никогда не покидает компьютер, поэтому изменения маршрутизации не влияют на то, как браузер отвечает на попытку соединения с 127.0.0.1. Вы добавляете сетевой переход и накладные расходы, а само поведение остаётся нетронутым. О том, как сетевой маршрут и среда выполнения страницы должны описывать одну и ту же конфигурацию, читайте в статье Сетевая согласованность браузера для защиты приватности, где описан воспроизводимый способ проверки этого соответствия.
Общее у этих вариантов то, что ни один не делает ответы единообразными. Они либо убирают ответ, что заметно и мешает работе, либо действуют на уровне, который соединения не видит. Цель, которая действительно соответствует проблеме, уже: когда страница пытается соединиться с часто опрашиваемым петлевым портом, результат не должен зависеть от того, слушает ли там служба. Разрешение имён - это отдельная поверхность, которую ни один из этих вариантов не затрагивает; читайте в статье Предотвращение утечек DNS: пути разрешения, прокси и проверки, где рассмотрены пути разрешения и порядок проверки на утечки.
Включение защиты портов
BotBrowser описывает защиту портов как функцию PRO. По умолчанию она выключена, и включить её можно флагом запуска или настройкой профиля. Вариант для командной строки это один флаг, добавленный к обычной команде запуска:
chrome --bot-profile="path/to/profile.enc" --bot-port-protection
Тот же переключатель можно записать в JSON профиля, что удобно для профилей, где защита должна быть включена всегда и флаг нельзя забыть:
{
"configs": {
"portProtection": true
}
}
Когда настройка находится в профиле, она применяется сразу после загрузки профиля, и дополнительный флаг не нужен. Если вы запускаете браузер через фреймворк автоматизации, добавьте тот же флаг в аргументы запуска так же, как любой другой флаг BotBrowser. Документация по защите портов показывает тот же флаг в запуске Playwright и в комбинированной настройке с прокси.
Документированное поведение таково: попытки соединения со страниц с часто опрашиваемыми портами ведут себя одинаково для петлевых адресов. Справочник по флагам CLI указывает покрываемый набор как 30 часто опрашиваемых портов для трёх форм адреса: блока IPv4 127.0.0.0/8, петлевого адреса IPv6 ::1 и имени хоста localhost. Руководство по защите портов описывает то же поведение, не называя числа.
Выбирайте флаг, когда защита нужна для одного запуска, например во время проверки. Выбирайте настройку профиля, когда конкретный профиль должен всегда её содержать. Команды, которые хранят скрипты запуска в системе контроля версий, часто предпочитают настройку профиля, потому что защищённый профиль остаётся защищённым, какой бы скрипт его ни запускал, а просмотр файла профиля показывает замысел. Помните, что функция по умолчанию выключена, поэтому профиль без этой настройки и запуск без флага работают без защиты.
Серверы без графического интерфейса и общие сборочные машины заслуживают отдельного замечания. Браузер на сервере, где размещены базы данных, агенты мониторинга и инструменты контейнеров, находится рядом со множеством локальных слушателей, и посещаемая им страница может увидеть такую же картину, как на рабочей станции. Если этот браузер входит в парк, который должен вести себя согласованно, особый набор слушателей одного сервера оказывается нежелательным отличием. Если задать параметр в профиле, который используют эти задания, поведение остаётся одинаковым и не зависит от каждого скрипта запуска.
Для планирования важны две детали. Во-первых, защита относится к попыткам, которые делают веб-страницы. Документация указывает, что локальные инструменты, подключающиеся напрямую, не затрагиваются, поэтому ваш терминал, клиент базы данных и редактор продолжают работать как раньше. Во-вторых, покрываемый набор это фиксированный список часто опрашиваемых портов, а не все порты компьютера. Если вам нужно покрытие порта вне этого списка, документация отправляет вас в поддержку, и не стоит считать, что он включён.
Проверка единообразных результатов на локальной тестовой службе
Проверка должна показать две вещи: результаты попыток со страницы единообразны при включённой защите, а ваши собственные инструменты по-прежнему работают. Обе проверки можно выполнить на вашем компьютере с помощью одноразовой службы. Делайте это только на своём компьютере. Проверка узлов, которыми вы не управляете, не является шагом верификации и здесь не рассматривается.
Запустите безобидную службу, привязанную к петлевому адресу, на порту, который вам не жалко занять:
python3 -m http.server 8080 --bind 127.0.0.1
Затем выполните проверки по порядку:
- Сделайте базовый прогон без защиты портов. Возьмите небольшую тестовую страницу, которую вы контролируете и загружаете в браузере, пусть её код попытается соединиться с вашей одноразовой службой и с неиспользуемым портом на том же адресе и запишет, чем закончилась каждая попытка.
- Запустите браузер снова с
--bot-port-protectionилиconfigs.portProtectionи повторите ту же страницу. При активной защите результат для открытого и неиспользуемого порта должен быть для страницы неотличим. - Повторите попытку для форм, которые называет документация: адрес IPv4 петлевого интерфейса, адрес IPv6 ::1 и имя хоста localhost. Результат должен быть единообразным для каждой формы, а не только для одной.
- Из терминала подключитесь к одноразовой службе напрямую, например командой
curl http://127.0.0.1:8080/. Она должна отвечать как обычно, потому что прямые соединения инструментов не затрагиваются. - Если вы зависите от того, что веб-страница общается с локальным приложением-компаньоном, проверьте эту интеграцию при включённой защите. Документация описывает согласованное поведение для попыток страниц к часто опрашиваемым портам, поэтому любой сценарий связи страницы с локальным приложением на одном из этих портов стоит проверить отдельно, прежде чем внедрять настройку.
- Запишите аргументы запуска, используемый профиль и результаты и повторяйте проверку после изменений профиля, сборки браузера или скриптов запуска.
Полезная запись короткая: форма адреса, порт, одноразовая это служба или неиспользуемый порт, и что наблюдала страница. Ограничивайтесь своими тестовыми портами. Записи, где перечислены лишь результаты для портов, которые вы открыли сами, достаточно, чтобы показать единообразие, и она не оставляет в общем документе перечня ваших настоящих служб.
Если базовый прогон уже выглядит единообразным, сравнение мало что даёт, потому что ваша тестовая страница не отличала два порта и без защиты. Если защищённый прогон всё ещё показывает разницу на порту, который, как вы ожидаете, покрыт, проверьте, что флаг или настройка профиля дошли до браузера, и сверьте порт с документацией. Порт вне покрываемого набора ведёт себя как прежде. Это вопрос покрытия, который стоит задать поддержке, а не обязательно неисправность.
Что поддерживает BotBrowser и что остаётся за его пределами
BotBrowser PRO поддерживает защиту портов через флаг --bot-port-protection или configs.portProtection в профиле и делает так, что попытки соединения веб-страниц с часто опрашиваемыми петлевыми портами (30 портов в 127.0.0.0/8, ::1 и localhost) ведут себя одинаково, поэтому страница не может составить карту ваших локальных служб. BotBrowser не может гарантировать покрытие портов вне документированных 30 или диапазонов локальной сети, таких как 192.168.x.x, не может изменить соединения, которые напрямую устанавливают локальные инструменты, и не заменяет защиту прокси, DNS, WebRTC и другие меры защиты от отпечатков.
Охват намеренно узкий. Адреса, которые называет документация, это петлевые адреса. Диапазоны, которыми пользуются другие устройства вашей сети, например 192.168.x.x, 10.x.x.x и 172.16.x.x, не входят в документированное покрытие, поэтому не называйте их защищёнными. Функция также лишь один слой из нескольких: ваш IP-адрес, DNS-запросы и кандидаты WebRTC это отдельные поверхности, которым нужна своя обработка, как и canvas, шрифтам и подобным признакам.
О соседних сетевых слоях читайте в материалах защита от утечек DNS, защита от утечек WebRTC и согласованность прокси, DNS и WebRTC. Перед тем как менять в своих заметках покрываемые диапазоны, число портов, уровень лицензии или состояние по умолчанию, перепроверьте документацию по защите портов и справочник по флагам CLI, потому что именно эти детали скорее всего изменятся между выпусками.
Источники
- Документация BotBrowser: защита портов
- Документация BotBrowser: справочник по флагам CLI
- WICG: Local Network Access
- RFC 1122: Requirements for Internet Hosts, Communication Layers
- RFC 4291: IP Version 6 Addressing Architecture
Итог
Включайте --bot-port-protection или configs.portProtection, когда видимый странице результат не должен зависеть от локальных слушающих процессов. Проверьте документированный набор из 30 портов и повторите проверку для 127.0.0.1, ::1 и localhost; одинаковый результат браузера не означает защиту частных адресов или портов вне набора.
Эта статья входит в руководство: Обзор настройки прокси: карта сетевых решений браузера
Похожие статьи
Обзор настройки прокси: карта сетевых решений браузера
СетьПредотвращение утечек DNS: пути разрешения, прокси и проверки
СетьUDP через SOCKS5: приватные маршруты QUIC и WebRTC
ПлатформаРазрешения Web Serial и жизненный цикл порта
СетьСогласованность прокси IPv4 и IPv6 в браузере
СетьНастройка прокси браузера: руководство по SOCKS5, HTTP и HTTPS
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.