Localhost-атака: как Meta, Яндекс и шпионское ПО эксплуатируют loopback-интерфейс

Дата: 7 апреля 2026
Статус: Верифицировано — исследование USENIX Security 26, POC опубликован
Оригинал исследования: localmess.github.io
Научная статья: Bridges to Self: Silent Web-to-App Tracking on Mobile via Localhost (USENIX Security 26)
POC (Meta/Яндекс): github.com/localmess/localhost-abuse
POC (VLESS обход split tunneling): github.com/runetfreedom/per-app-split-bypass-poc


Оглавление

  1. Корневая проблема: архитектура loopback в ОС
  2. Яндекс: localhost-трекинг с 2017 года
  3. Meta (Facebook): WebRTC STUN SDP Munging
  4. Побочный эффект: утечка истории браузера
  5. VLESS/xray/sing-box: та же дыра, другой вектор
  6. Happ: бэкдор через xray API HandlerService
  7. Протокол SOCKS5: как работает аутентификация (RFC 1928/1929)
  8. xray-core: настройка аутентификации SOCKS5 inbound
  9. sing-box: настройка аутентификации SOCKS/mixed inbound
  10. Сводная таблица атак и защит
  11. Как защитить VPN-клиенты
  12. Статус браузеров и патчей
  13. Хронология событий
  14. Источники

1. Корневая проблема: архитектура loopback в ОС

Все описанные атаки — трекинг Meta, трекинг Яндекса, и уязвимость VLESS-клиентов — эксплуатируют одну и ту же фундаментальную архитектурную слабость: неконтролируемый доступ к loopback-интерфейсу (127.0.0.1).

Как устроен loopback

┌─────────────────────────────────────────────────────┐
│                    Android / Windows                 │
│                                                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐          │
│  │ App A    │  │ App B    │  │ Browser  │          │
│  │ (Яндекс) │  │ (Шпион)  │  │ (Chrome) │          │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘          │
│       │              │              │                │
│       ▼              ▼              ▼                │
│  ┌──────────────────────────────────────────┐       │
│  │         127.0.0.1 (loopback)             │       │
│  │   Общий для ВСЕХ процессов устройства    │       │
│  │   НЕ маршрутизируется через VPN/TUN      │       │
│  │   НЕ изолирован между профилями          │       │
│  │   НЕ требует специальных разрешений      │       │
│  └──────────────────────────────────────────┘       │
└─────────────────────────────────────────────────────┘

Что ОС разрешает на loopback

ДействиеAndroidWindowsiOS
Слушать порт на localhost✅ Любое приложение с INTERNET✅ Любой процесс✅ Ограничено фоновым режимом
Подключиться к чужому порту на localhost✅ Без ограничений✅ Без ограничений✅ Технически возможно
Сканировать все порты localhost✅ За секунды✅ За секунды⚠️ Ограничено фоном
Изоляция между профилями (Knox/Shelter)❌ Loopback общийN/AN/A
Изоляция VPN/TUN от loopback❌ Loopback вне VPN❌ Loopback вне TUN
JavaScript из браузера → localhost✅ Без согласия✅ Без согласия

Почему loopback не изолирован

Это by design, а не баг ОС. Приложениям легитимно нужен localhost для:

  • Межпроцессного взаимодействия (IPC)
  • Локальных серверов разработки
  • Коммуникации между компонентами одного приложения

Проблема в том, что никто не предусмотрел, что это станет вектором атаки для трекинга и обнаружения VPN.


2. Яндекс: localhost-трекинг с 2017 года

Архитектура атаки

┌─────────────────────┐     ┌──────────────────────────┐
│   Мобильный браузер  │     │  Нативное приложение     │
│   (Chrome/Firefox)   │     │  Яндекса (Карты/Браузер) │
│                      │     │                          │
│  ┌────────────────┐  │     │  ┌─────────────────────┐ │
│  │ Яндекс.Метрика │  │     │  │ SDK Яндекс.Метрики  │ │
│  │ JavaScript     │──┼─────┼─▶│ Слушает TCP порты:  │ │
│  │                │  │ HTTP│  │ 29009, 30102 (HTTP)  │ │
│  │                │  │ на  │  │ 29010, 30103 (HTTPS) │ │
│  │                │◀─┼─────┼──│                     │ │
│  └───────┬────────┘  │200OK│  │ Отвечает: AAID +    │ │
│          │           │+IDs │  │ зашифрованные ID     │ │
│          ▼           │     │  └─────────────────────┘ │
│  Отправляет ID на    │     │                          │
│  mc.yango.com        │     │                          │
└─────────────────────┘     └──────────────────────────┘

Пошаговый процесс

Шаг 1. Пользователь открывает приложение Яндекса (Карты, Навигатор, Браузер, Поиск, Go). Приложение уходит в фон и запускает фоновый сервис, слушающий порты.

Шаг 2. Приложение обращается к startup.mobile.yandex.net для получения конфигурации:

{
  "ports": [30102, 29009],
  "first_delay_seconds": 259200
}

Параметр first_delay_seconds задаёт задержку перед началом прослушивания (~3 дня после установки). Вероятно, для маскировки — не начинать слушать сразу после установки.

Шаг 3. Пользователь открывает браузер, заходит на сайт с Яндекс.Метрикой (~3 млн сайтов по BuiltWith, ~575K по HTTP Archive).

Шаг 4. JavaScript Яндекс.Метрики запрашивает зашифрованные параметры с серверов Яндекса.

Шаг 5. Скрипт отправляет HTTP/HTTPS-запросы на localhost:

  • http://127.0.0.1:29009/...
  • https://yandexmetrica.com:30103/... ← домен резолвится в 127.0.0.1

Ключевой трюк: домен yandexmetrica.com сконфигурирован резолвиться в 127.0.0.1. Это позволяет использовать HTTPS (порты 29010, 30103) — запросы выглядят как обычные HTTPS к «настоящему» домену, но идут на localhost. Обнаружить это стандартными средствами практически невозможно.

Шаг 6. SDK Яндекс.Метрики в нативном приложении получает запрос и отвечает HTTP 200 OK с телом, содержащим Base64-закодированные бинарные данные:

  • Android Advertising ID (AAID)
  • Google Advertising ID
  • UUID, специфичные для Яндекса

Шаг 7. JavaScript получает эти идентификаторы и отправляет их на mc.yango.com вместе с зашифрованными параметрами и информацией о посещённой странице.

Результат: Яндекс связывает эфемерную веб-сессию (кука, IP, User-Agent) с постоянным идентификатором устройства (AAID). Пользователь деанонимизирован на всех сайтах с Яндекс.Метрикой.

Проверенные приложения Яндекса

ПриложениеPackage nameТестовая версияПорты
Яндекс.Картыru.yandex.yandexmaps23.5.029009, 30102
Яндекс.Навигаторru.yandex.yandexnavi23.5.029009, 30102
Яндекс.Браузерcom.yandex.browser25.4.1.10029009, 30102
Яндекс.Поискcom.yandex.searchapp25.4129009, 30102
Метро в Европеru.yandex.metro3.7.329009, 30102
Яндекс Go: Таксиru.yandex.taxi5.24.129009, 30102

Что обходит этот метод

Метод работает даже если пользователь:

  • ❌ Не залогинен в Яндексе в браузере
  • ❌ Использует режим инкогнито
  • ❌ Очистил куки и данные браузера
  • ❌ Сбросил рекламный идентификатор Android

3. Meta (Facebook): WebRTC STUN SDP Munging

Архитектура атаки

┌─────────────────────┐     ┌──────────────────────────┐
│   Мобильный браузер  │     │  Facebook / Instagram    │
│   (Chrome/Edge)      │     │  (нативное приложение)   │
│                      │     │                          │
│  ┌────────────────┐  │     │  ┌─────────────────────┐ │
│  │ Meta Pixel JS  │  │     │  │ Фоновый сервис      │ │
│  │                │──┼─────┼─▶│ TCP: 12387, 12388   │ │
│  │ SDP Munging:   │  │WebRTC│  │ UDP: 12580-12585    │ │
│  │ ice-ufrag =    │  │STUN │  │      (STUN)         │ │
│  │ _fbp cookie    │  │     │  │ UDP: 12586-12591    │ │
│  │                │  │     │  │      (TURN)         │ │
│  └───────┬────────┘  │     │  └─────────────────────┘ │
│          │           │     │         │                 │
│          ▼           │     │         ▼                 │
│  Отправляет _fbp на  │     │  GraphQL → graph.        │
│  facebook.com/tr     │     │  facebook.com/graphql    │
│  + URL, событие,     │     │  + _fbp + Device ID     │
│  метаданные          │     │  + Facebook Account ID   │
└─────────────────────┘     └──────────────────────────┘

Техника SDP Munging

SDP Munging — это манипуляция полями SDP (Session Description Protocol) в WebRTC-соединении для передачи произвольных данных.

Meta Pixel вставляет значение куки _fbp в поле ice-ufrag SDP-предложения. При WebRTC handshake генерируется STUN Binding Request, который отправляется на localhost UDP-порты 12580-12585. Нативное приложение Facebook/Instagram слушает эти порты и извлекает _fbp из STUN-пакета.

Почему это невидимо:

  • WebRTC STUN-трафик не отображается в Chrome DevTools
  • Нет HTTP-запросов, которые можно было бы перехватить в инспекторе
  • Сетевая активность происходит на уровне UDP, ниже HTTP-слоя

Эволюция техник Meta

МетодНачалоКонецПортыОбнаружимость
HTTPСентябрь 2024Октябрь 2024TCP 12387Средняя (видно в DevTools)
WebSocketНоябрь 2024Январь 2025TCP 12387Средняя
WebRTC STUN + SDP MungingНоябрь 2024Июнь 2025UDP 12580-12585Очень низкая
WebRTC TURN (без SDP Munging)Май 2025Июнь 2025UDP 12586-12591Низкая

Meta 4 раза сменила технику за 9 месяцев, каждый раз усложняя обнаружение.

О куке _fbp

  • Third most popular first-party cookie в интернете (Web Almanac 2024)
  • Присутствует на ~25% из топ-1М сайтов
  • Срок жизни: 90 дней
  • First-party cookie = разная на каждом сайте → нельзя использовать для кросс-сайтового трекинга
  • НО: через localhost-атаку Meta связывает разные _fbp с одним устройством → кросс-сайтовый трекинг становится возможен

Масштаб

РегионСайтов с Meta Pixel (из 100K)Без согласия пользователя
США17,22313,468 (78.2%)
Европа15,67711,890 (75.8%)
РегионСайтов с Яндекс.Метрикой (из 100K)Без согласия пользователя
США1,3121,095 (83.5%)
Европа1,2601,064 (84.4%)

Пошаговый процесс Meta

  1. Пользователь открывает Facebook/Instagram → приложение уходит в фон → слушает TCP 12387/12388 и UDP 12580-12585
  2. Пользователь открывает браузер → заходит на сайт с Meta Pixel (~5.8 млн сайтов)
  3. Meta Pixel JS читает куку _fbp
  4. JS создаёт WebRTC peer connection с SDP Munging: ice-ufrag = <_fbp value>
  5. STUN Binding Request с _fbp в поле ice-ufrag летит на 127.0.0.1:12580-12585
  6. Facebook/Instagram получают _fbp
  7. Приложение отправляет GraphQL на graph.facebook.com/graphql: _fbp + Device ID + Facebook Account ID
  8. Meta связывает: веб-сессия ↔ устройство ↔ аккаунт Facebook

4. Побочный эффект: утечка истории браузера

Поскольку Яндекс использует обычные HTTP-запросы (не WebRTC), любое стороннее приложение, слушающее те же порты, может перехватить эти запросы и прочитать заголовок Origin, который содержит URL посещённого сайта.

Кто уязвим

БраузерЯндекс (утечка истории)Meta (утечка истории)Защита
Chrome✅ Уязвим✅ УязвимChrome 137+ — блокировка портов и SDP Munging
Firefox✅ Уязвим❌ Не затронутВ разработке
Edge✅ Уязвим✅ УязвимНеизвестно
Brave❌ Защищён❌ ЗащищёнС 2022: blocklist + запрос согласия на localhost
DuckDuckGo⚠️ Минимально❌ ЗащищёнBlocklist (3 домена Яндекса отсутствовали — исправлено)

Работает в режиме инкогнито: ДА. Инкогнито не влияет на доступ к localhost.

POC-демонстрация

Исследователи создали POC-приложение (github.com/localmess/localhost-abuse), которое:

  1. Слушает порты 29009, 30102 (как приложения Яндекса)
  2. Перехватывает HTTP-запросы от Яндекс.Метрики
  3. Извлекает Origin заголовок
  4. Отображает список посещённых сайтов в реальном времени

5. VLESS/xray/sing-box: та же дыра, другой вектор

Связь с Meta/Яндекс

Meta и Яндекс доказали: localhost на Android не изолирован, и это можно массово эксплуатировать. Уязвимость VLESS-клиентовтот же фундаментальный баг, но другой вектор атаки.

АспектMeta/ЯндексVLESS-клиенты
Что на localhostТрекинг-сервис приложенияSOCKS5-прокси без аутентификации
Кто атакуетJavaScript с веб-страницыШпионский модуль в приложении
Что получает атакующийDevice ID (AAID) + связь с аккаунтомВыходной IP VPN-сервера
ЦельДеанонимизация + таргетированная рекламаБлокировка VPN-серверов
Фундаментальная проблемаLoopback не изолированLoopback не изолирован
Knox/Shelter помогает?НетНет
Инкогнито помогает?НетN/A

Как эксплуатируется VLESS

┌──────────────────┐
│  Шпионский модуль │  (Яндекс/WB/Ozon/гос.приложение)
│  в приложении     │
└────────┬─────────┘
         │ 1. Скан портов localhost (секунды)
         ▼
┌──────────────────────┐
│ 127.0.0.1:10808      │  SOCKS5 без аутентификации
│ (xray-core inbound)  │
└────────┬─────────────┘
         │ 2. SOCKS5 handshake (method 0x00 = NO AUTH)
         │ 3. CONNECT ifconfig.me:80
         ▼
┌──────────────────┐
│  xray-core       │ → VPN-сервер → ifconfig.me
│  outbound        │ ← ответ: "185.xxx.xxx.xxx"
└──────────────────┘
         │ 4. Шпион получает выходной IP
         ▼
    РКН блокирует сервер

Почему per-app split tunneling не помогает

                        VpnService (TUN)
                       ┌──────────────┐
Обычное приложение ──▶ │  tun2socks   │ ──▶ xray SOCKS5 ──▶ VPN-сервер
                       └──────────────┘           ▲
                                                   │
Шпион ──▶ 127.0.0.1:10808 ────────────────────────┘
          (минуя VpnService)

VpnService перехватывает трафик через TUN-интерфейс. Но подключение к 127.0.0.1 не проходит через TUN — это внутренний loopback. Split tunneling бессилен.

Почему Knox/Shelter/Island не помогают

Android Private Spaces изолируют файловую систему и VpnService, но loopback-интерфейс общий для всех профилей. Процесс из Knox видит 127.0.0.1:10808 основного профиля.

Контекст: методичка Минцифры РФ

Минцифры разослало аккредитованным IT-компаниям методичку по обнаружению VPN. Характерные порты из методички:

ТипПорты
SOCKS1080, 9000, 5555, 16000-16100
HTTP80, 443, 3128, 3127, 8000, 8080, 8081, 8888
Прозрачные Proxy80, 443, 4080, 7000/7044, 8082, 12345
Tor9050, 9051, 9150

Стандартные порты xray (10808) и nekobox (2080) пока не указаны, но полный скан 65535 портов на localhost — секунды.

Список уязвимых VLESS-клиентов

КлиентПлатформаЯдроSOCKS5 authСтатус
HappiOSxray🔴 Особо опасен (API без auth)
v2RayTunAndroidxray🟡 Обещали исправить
V2BOXiOS/Androidxray🟡 Уязвим
v2rayNGAndroidxray🟡 Уязвим (порт 10808)
HiddifyAndroid/iOSsing-box🟡 Уязвим
ExclaveiOSxray🟡 Уязвим
Npv TunnelAndroidxray🟡 Уязвим
Neko BoxAndroidsing-box🟡 Уязвим (порт 2080)
HusiAndroidsing-box🟢 Можно настроить
SFA (sing-box)Androidsing-box🟢 Ручной JSON
saeeddev94/xrayAndroidxray🟢 F-Droid, ручной JSON

6. Happ: бэкдор через xray API HandlerService

Клиент Happ — отдельная категория. Помимо уязвимого SOCKS5, он включает xray gRPC API с HandlerService БЕЗ аутентификации.

Сервисы xray API

СервисНазначениеОпасность
StatsServiceСтатистика трафика, онлайн-пользователиНизкая
LoggerServiceУправление логированиемНизкая
HandlerServiceДобавление/удаление inbound/outbound, дамп конфигов, управление пользователями🔴 Критическая
RoutingServiceУправление маршрутизациейСредняя
ReflectionServiceСписок доступных APIСредняя

gRPC методы HandlerService

МетодЧто делает
AddInboundДобавить новый inbound
RemoveInboundУдалить inbound
AlterInboundИзменить inbound
AddOutboundДобавить outbound
RemoveOutboundУдалить outbound
AlterOutboundИзменить outbound
GetInboundUsersПолучить пользователей (включая ключи)

Цепочка атаки

Шпион → скан портов → gRPC API (без auth)
     → ReflectionService → список методов
     → HandlerService → дамп outbound конфига
     → ключ шифрования + IP сервера + SNI
     → [+ вторая уязвимость конфигурации] → расшифровка трафика

Позиция Happ: заявили, что API нужен «для статистики». Это ложь — для статистики достаточно StatsService. При смене конфига Happ перезапускает xray целиком, а не использует HandlerService.

Рекомендация: немедленно удалить Happ. Заблокировать Happ/* по UserAgent на серверах подписок. Один пользователь с Happ компрометирует весь сервер.


7. Протокол SOCKS5: как работает аутентификация (RFC 1928/1929)

Зачем нужна аутентификация SOCKS5

Без аутентификации SOCKS5-прокси — это открытая дверь: кто угодно может подключиться и маршрутизировать через него трафик. В контексте VPN это означает, что шпионский модуль может:

  • Обнаружить прокси сканированием портов
  • Подключиться без учётных данных
  • Узнать выходной IP VPN-сервера
  • Гонять через прокси произвольный трафик

Аутентификация добавляет барьер: без знания логина/пароля подключение отклоняется.

Фаза 1: Согласование метода (RFC 1928)

Клиент → Сервер:
+-----+----------+----------+
| VER | NMETHODS | METHODS  |
+-----+----------+----------+
| 0x05|   0x01   |   0x02   |   ← «Я хочу SOCKS5, предлагаю метод 0x02 (пароль)»
+-----+----------+----------+

Сервер → Клиент:
+-----+--------+
| VER | METHOD |
+-----+--------+
| 0x05|  0x02  |   ← «Принято, используем метод 0x02»
+-----+--------+

Методы аутентификации:

  • 0x00NO AUTHENTICATION REQUIRED ← уязвимый вариант
  • 0x01 — GSSAPI
  • 0x02USERNAME/PASSWORD ← безопасный вариант
  • 0xFF — нет подходящего метода (отказ)

Фаза 2: Аутентификация по логину/паролю (RFC 1929)

Клиент → Сервер:
+-----+------+----------+------+----------+
| VER | ULEN |  UNAME   | PLEN |  PASSWD  |
+-----+------+----------+------+----------+
| 0x01| 0x08 | "user123"| 0x0C | "pass456abc"|
+-----+------+----------+------+----------+

Сервер → Клиент:
+-----+--------+
| VER | STATUS |
+-----+--------+
| 0x01|  0x00  |   ← 0x00 = успех, любое другое = отказ
+-----+--------+

Поля:

  • VER = 0x01 (версия подпротокола аутентификации)
  • ULEN = длина логина (1-255 байт)
  • UNAME = логин
  • PLEN = длина пароля (1-255 байт)
  • PASSWD = пароль

⚠️ Важно: логин и пароль передаются открытым текстом. RFC 1929: «Since the request carries the password in cleartext, this subnegotiation is not recommended for environments where ‘sniffing’ is possible and practical.» Но для localhost это не проблема — трафик не выходит за пределы устройства.

Фаза 3: Запрос (после успешной аутентификации)

Клиент → Сервер:
+-----+-----+------+------+----------+----------+
| VER | CMD | RSV  | ATYP | DST.ADDR | DST.PORT |
+-----+-----+------+------+----------+----------+
| 0x05| 0x01| 0x00 | 0x01 | IP addr  |  port    |
+-----+-----+------+------+----------+----------+

CMD:

  • 0x01 — CONNECT (TCP)
  • 0x02 — BIND
  • 0x03 — UDP ASSOCIATE

Проблема UDP ASSOCIATE

UDP ASSOCIATE (CMD = 0x03) создаёт UDP-ретранслятор. Но: после успешной TCP-аутентификации UDP-датаграммы не проходят повторную аутентификацию.

UDP-датаграмма (RFC 1928, Section 7):
+-----+------+------+----------+----------+----------+
| RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
+-----+------+------+----------+----------+----------+
|  2  |  1   |  1   | Variable |    2     | Variable |
+-----+------+------+----------+----------+----------+

В заголовке UDP-датаграммы нет поля для аутентификации. RFC 1928 допускает опциональное шифрование/целостность, но большинство реализаций (включая xray и sing-box) не реализуют per-packet auth для UDP.

Вывод: для полной защиты от localhost-атак UDP нужно отключать или блокировать фаерволом.


8. xray-core: настройка аутентификации SOCKS5 inbound

Уязвимая конфигурация (как есть сейчас)

{
    "inbounds": [
        {
            "tag": "socks-in",
            "listen": "127.0.0.1",
            "port": 10808,
            "protocol": "socks",
            "settings": {
                "auth": "noauth",
                "udp": true
            }
        }
    ]
}

Проблемы:

  • "auth": "noauth" — любой процесс на устройстве может подключиться
  • "udp": true — UDP тоже доступен без ограничений
  • Порт 10808 — стандартный, легко угадывается

Безопасная конфигурация

{
    "inbounds": [
        {
            "tag": "socks-in",
            "listen": "127.0.0.1",
            "port": 10808,
            "protocol": "socks",
            "settings": {
                "auth": "password",
                "accounts": [
                    {
                        "user": "xf_a8b3c2d1",
                        "pass": "7e4f91d0c3b8a2e5"
                    }
                ],
                "udp": false
            }
        }
    ]
}

Что изменилось:

  • "auth": "password" — требуется аутентификация
  • "accounts" — массив учётных записей {user, pass}
  • "udp": false — UDP отключён (убирает вектор атаки через UDP ASSOCIATE)

Поля конфигурации xray SOCKS inbound

ПолеТипПо умолчаниюОписание
auth"noauth" / "password""noauth"Режим аутентификации
accounts[{user, pass}]Учётные записи (только при auth: "password")
udpbooleanfalseВключение UDP ASSOCIATE
ipstringautoIP для UDP-ответов
userLevelnumber0Уровень политик

Рекомендации для xray-клиентов

  1. Генерировать credentials при каждом запуске — рандомные user/pass, не хардкодить
  2. Отключить UDP ("udp": false) — UDP не аутентифицируется per-packet
  3. Слушать только на 127.0.0.1 — никогда на 0.0.0.0
  4. Рандомизировать порт — не использовать стандартный 10808
  5. Не включать HandlerService в API — достаточно StatsService/LogService

9. sing-box: настройка аутентификации SOCKS/mixed inbound

Уязвимая конфигурация

{
    "inbounds": [
        {
            "type": "mixed",
            "tag": "mixed-in",
            "listen": "0.0.0.0",
            "listen_port": 2080
        }
    ]
}

Проблемы:

  • Нет массива users — аутентификации нет
  • "listen": "0.0.0.0" — доступен из сети (ещё хуже чем localhost)
  • Порт 2080 — стандартный для nekobox

Безопасная конфигурация

{
    "inbounds": [
        {
            "type": "mixed",
            "tag": "mixed-in",
            "listen": "127.0.0.1",
            "listen_port": 2080,
            "users": [
                {
                    "username": "sb_d4c1a7f2",
                    "password": "9e2f5b83a1c7d0e4"
                }
            ]
        }
    ]
}

Поля конфигурации sing-box SOCKS/mixed inbound

ПолеТипОписание
type"socks" / "mixed"mixed поддерживает SOCKS4/4a/5 + HTTP
listenstringАдрес прослушивания
listen_portnumberПорт
users[{username, password}]Учётные записи (без этого поля — без auth)
set_system_proxybooleanАвтоматическая системная прокси-настройка

Разница SOCKS vs Mixed

Возможностьtype: "socks"type: "mixed"
SOCKS4/4a
SOCKS5
HTTP-прокси
users (аутентификация)✅ (для SOCKS и HTTP)
set_system_proxy

Позиция разработчика sing-box

Разработчик sing-box считает эту проблему «skill issue» клиентов: sing-box не создаёт mixed inbound автоматически — это делают конкретные клиенты и генераторы конфигов. Если не добавлять mixed inbound в конфиг, прокси не будет.


10. Сводная таблица атак и защит

МеханизмПротив Meta/ЯндексПротив VLESS-сканаПротив Happ API
SOCKS5 auth (password)N/A✅ Блокирует подключениеN/A
Отключение UDPN/A✅ Убирает векторN/A
Рандомный портN/A⚠️ Замедляет, не блокируетN/A
iptables/root✅ Можно заблокировать✅ Можно заблокировать
Knox/Shelter/Island❌ Не помогает❌ Не помогает
Режим инкогнито❌ Не помогаетN/AN/A
Очистка куки❌ Не помогаетN/AN/A
Brave Browser✅ Blocklist + consentN/AN/A
Chrome 137+✅ Блокировка портовN/AN/A
Отключение HandlerServiceN/AN/A✅ Убирает API
Блокировка Happ по UserAgentN/AN/A✅ На сервере
Отдельное устройство✅ Физическая изоляция
Windows Firewall (process)

11. Как защитить VPN-клиенты

Для разработчиков клиентов

  1. SOCKS5 auth по умолчанию — генерировать рандомные credentials при каждом запуске, передавать их только доверенным приложениям
  2. Отключить UDP в SOCKS5 inbound — UDP ASSOCIATE не поддерживает per-packet auth
  3. Рандомизировать порт — не стандартные 10808/2080/1080
  4. Только 127.0.0.1 — никогда 0.0.0.0
  5. Не включать xray API HandlerService — для статистики хватит StatsService/LogService
  6. На Android с root: добавить iptables-правила, ограничивающие доступ к порту по UID процесса

Для пользователей Android

  1. Использовать клиенты с SOCKS5 auth: Husi, SFA, saeeddev94/xray
  2. Удалить Happ немедленно
  3. Держать российское ПО на отдельном устройстве
  4. Не полагаться на Knox/Shelter — loopback не изолирован
  5. С root: iptables -I OUTPUT -p tcp -d 127.0.0.1 --dport 10808 -j DROP для всех кроме VPN-клиента

Для пользователей Windows

  1. Windows Firewall: правила на блокировку доступа к портам 10808/10809 для всех процессов кроме xray.exe и доверенных
  2. В xray routing: process name для разрешённых приложений
  3. Рандомный порт вместо стандартного 10808

Для администраторов серверов

  1. Раздельные входной/выходной IP — утечка выходного не компрометирует входной
  2. CloudFlare WARP на выходе — маскировка выходного IP
  3. geoip:ru → block на сервере — шпион не сможет связать трафик
  4. Блокировка Happ по UserAgent Happ/*

Маршрутизация

На клиенте:

geoip:ru      → direct    (российские IP напрямую)
geoip:private → direct    (локальные сети)
остальное     → proxy     (через VPN)

На сервере:

geoip:ru      → block     (запретить выход на РФ)
остальное     → freedom   (разрешить)

12. Статус браузеров и патчей

Meta Pixel

ДатаСобытие
Сентябрь 2024Начало HTTP-коммуникации с localhost
Ноябрь 2024Переход на WebSocket, затем WebRTC STUN
Май 2025Добавлен WebRTC TURN (обход блокировки SDP Munging)
26 мая 2025Chrome 137 — блокировка SDP Munging и абьюзимых портов
3 июня 2025Meta полностью прекратила localhost-трекинг, код удалён

Яндекс.Метрика

ДатаСобытие
Февраль 2017Начало HTTP-коммуникации с localhost
Май 2018Добавлен HTTPS (порты 29010, 30103)
Июнь 2025Яндекс сообщил о прекращении использования и удалении функции

Браузеры

БраузерСтатусДетали
Chrome 137+✅ ИсправленоБлокировка портов + SDP Munging
Brave 1.54+✅ Защищён с 2022Blocklist + localhost consent
DuckDuckGo✅ ИсправленоОбновлён blocklist
Firefox 139🟡 В разработкеПатч в процессе
Edge❌ НеизвестноChromium-based, должен следовать за Chrome

VLESS-клиенты

На 7 апреля 2026 ни один массовый VLESS-клиент не добавил SOCKS5 аутентификацию, несмотря на уведомление 10 марта 2026.


13. Хронология событий

ДатаСобытие
Февраль 2017Яндекс начинает localhost-трекинг через HTTP
Май 2018Яндекс добавляет HTTPS-канал (yandexmetrica.com → 127.0.0.1)
2022Brave добавляет защиту localhost (consent + blocklist)
Сентябрь 2024Meta начинает localhost-трекинг через HTTP
Ноябрь 2024Meta переходит на WebRTC STUN SDP Munging
10 марта 2026runetfreedom уведомляет разработчиков VLESS-клиентов об уязвимости SOCKS5
Апрель 2026Минцифры рассылает методичку по обнаружению VPN
7 апреля 2026Публикация уязвимости VLESS-клиентов, ни один клиент не исправлен
26 мая 2025Chrome 137 блокирует SDP Munging и абьюзимые порты
3 июня 2025Meta полностью удаляет код localhost-трекинга
Июнь 2025Публикация исследования USENIX Security 26 (localmess.github.io)

14. Источники

Исследование Meta/Яндекс (LocalMess)

Уязвимость VLESS

Документация протоколов

Защита браузеров