Методичка Минцифры по выявлению VPN

Требование регулятора-цензора. Ну и никто не говорил о явном шпионе с описанием “слежка”. Речь о приложениях, которые легально собирают данные в рамках политики конфиденциальности, расширенной под давлением регулятора.

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

WeChat и AliPay как минимум.
Также у правительства Китая есть доступ ко всем данным (сервера физически находятся внутри страны и у них есть доступ к ключам шифрования), который Apple собирает со своих пользователей.

Вы процитировали источник, который опровергает вашу же позицию.

“This function will successfully connect so long as the interface is one of the utun interfaces created by the VPNs, or a physical interface that is not used by the VPNs.”

en0/другой интерфейс (неважно) - это буквально физический интерфейс, VPN его не использует (VPN использует utun*). Значит, привязка к ним работает. Именно это и является механизмом обхода туннеля.

Насчёт разрешения Local Network - оно регулирует доступ к устройствам в локальной сети через Bonjour/mDNS. Привязка сокета к физическому интерфейсу для выхода в интернет - это другой уровень, и он этого разрешения не требует. Это задокументировано Symantec как конкретная уязвимость именно на iOS, без каких-либо оговорок о необходимых “разрешений”:

“Symantec researchers found that third-party applications on both iOS and macOS can evade this [VPN routing] method by explicitly binding a network socket to the IP address of a physical network interface. […] This means that it isn’t tunneled through the VPN client’s virtual interface, regardless of whether the traffic is included in the VPN route table.”

Никакого упоминания о разрешениях нет, потому что их не требуется.

Насчёт того, что говорил ValdikSS: он сказал “любой сетевой интерфейс”, и это технически верно именно потому, что и utun*, и en0 доступны. Сужать его слова до “только при каких-то условиях” - это додумывание за автора.

includeAllNetworks как контраргумент, если что, тоже не всегда работает: Mullvad в марте 2025 года опубликовали подробный технический разбор того, почему они до сих пор не могут его включить - обновление приложения через App Store полностью лишает смартфон сетевого подключения. Баг-репорт отправлен Apple в феврале 2025 года, ответа нет. Проблема на веб-сайте Mullvad до сих пор числится как нерешённая для всех версий iOS.

Не в теме, но иронично, как команда исследователей за TunnelCrack назвала iOS наиболее уязвимыми к этой уязвимости, а Android - наименее…:

We found that VPNs for iPhones, iPads, MacBooks, and macOS are extremely likely to be vulnerable, that a majority of VPNs on Windows and Linux are vulnerable, and that Android is the most secure with roughly one-quarter of VPN apps being vulnerable.

Google, допустим (и то не факт). Насчёт RuStore и всё уже давно понятно. Поинт был в том, что смысла нет ставить надежду на регулятора магазина приложений, если он же не отказывается выполнять требования цензора.

Да, всё верно.

Только что создал iOS приложение, выключил Background App Refresh, и оно всё равно в фоне даже после того как я полторы минуты прождал с выключенным VPN в самом VPN клиенте – при включении VPN оно тут же задетектило utun4 и через него смогло попасть в туннель и узнать IP адрес.

Более того, оно и вне VPN туннеля смогло через просто Wi-Fi наружу пойти и узнать выходной IP адрес DIRECT подключения. Во время включенного VPN (через en0).

Никаких разрешений оно не потребовало.

Только “уязвимостью” конечно я бы это не называл всё равно. В любом случае, пока VPN выключен, utun4 оно не видит. А иначе – любые подключения идут через туннель, без иллюзий. Shotcuts Automation – это фигня полная, от шпионажа это не спасет, в фоне всё работает и детектится.

Но мы всё равно додумывали не в том ключе. Дефолтным интерфейсом при включении VPN всё равно становится utun4 и всё равно через него бы пошло, разрешения не нужны. Так что про виртуалки внутри отдельных процессов всё равно пока не факт что exposed.

Ну и судя по всему, теперь “всё в туннель” на конечных устройствах теперь не помогает. Оно итак может узнать локацию ТСПУ через direct IP выбрав интерфейс en0… KillSwitch опции в v2box нету..

Походу гарантировать отсутствие утечек можно только со своего OpenWRT роутера.

Ну короче, как я и думал. Если хочется полной защиты, надо либо отдельный телефон, либо удаленную виртуалку поднимать, и к ней с телефона подключаться по RDP.

Только я не понимаю смысл этого. От утечек в DIRECT защитит только полное отключение LTE модуля, и whitelisted (к 1 IP) на уровне ядра OpenWRT Wi-Fi роутер. На смартфонах и ПК. Иначе даже гипервизор со вложенными гипервизорами не защитит от утечек в direct.

А от утечек входного IP – второй IP на выход.

Это считается за первый хоп, который могут прижать в любой момент. Иначе ничего не мешало бы VPN подключения под этот протокол маскировать.

На рутированных ведрах можно использовать iptables -m owner для блокировки отсылки через конкретный интерфейс с конкретного приложения. uid можно узнавать в шелле по package name, чтобы намертво не привязываться. Это ядерный киллсвитч, который при правильном автозапуске iptables гарантированно отрежет возможность что-либо слать прямо на уровне ядра linux, и неважно что там в кишках userland творится

Есть ли годные решения (обеспечивающие удобство пользования на уровне локального), позволяющие использовать андроид как тонкий клиент для другого андроида (эмулятора)?

Это для белых списков топ решение. Неубиваемое.

Для RDP – WebRTC – отлично.
А с Android вы с 90% вероятностью будете в БС ходить всё равно.

Ну так происходит на всех платформах по умолчанию, именно потому что VPN был создан не как инструмент обхода блокировок.

Кажется, уже реально проще будет нести 2-й телефон со всеми шпионскими приложениями, и если нужно, подключиться к его точке доступа с основного телефона (TTL можно модифицировать на рутированных устройствах, чтобы невозможно было понять, это трафик с раздачи или нет. Root скрывается довольно легко для рос. приложений, которые проверяют его наличие). “Подозрительный” (на VPN) трафик будет тогда совмещаться с “чистым” (на рос. приложения и сервисы). Но если вам удобнее настроить и нести свой роутер, то, как говорится, all power to you.

Я прогнал Этой прогой свою схему с раздельным туннелем. Максимум что он угадал - реальный ip, который от него никто не скрывал. Входящий ip не знает, исходящий тоже. Попытался показать мне какие то адреса но это судя по всему какие то промежуточные узлы непонятно чего.

Насколько я понимаю ничего не поможет пожилым и не сильно, если в телефоне куча приложений стукачей. Банки, маркетплэйсы.. нужно чистую мобилку.

Я бы рассматривал ещё как вариант, просто сказать им держать туннель 24/7 – у меня те кто пользуются моим туннелем так и делают. А настроил я по этой схеме.

В долгосрочной перспективе, возможно может потребоваться резидентская нода (выход) или пускать трафик для приложений кто заблокировал warp в direct (должен быть per-app split).

Пока – должно работать с warp выходом (для большинства сайтов). От шпионов, самое главное, защищает. Пожилым людям делать, – ничего не надо.

В методичке много написано о внедрении шпионских метрик в клиентские приложения, что как раз является наименьшей проблемой, так как split tunneling на уровне приложений, контейнеризация и т.д. позволяют обходить их на любой платформе. В соседних темах даже звучал радикальный вариант удаления всех потенциально скомпрометированных российских приложений со смартфонов и переход на веб-версии сервисов в браузере. Я же считаю, что это не панацея.

В недавней статье с разбором шпионской метрики, встроенной в Max, было выявлено что он, помимо прочего, пытается определять доступность main.telegram.org. На уровне изолированного приложения с настроенным split tunneling такая проверка не страшна, но в будущем такие же метрики наверняка будут встроены в веб-приложения российских сервисов.

Split tunneling от такой атаки не поможет. В этой схеме вы обращаетесь на, допустим, скомпрометированный ozon.ru со своего домашнего ip адреса (если разделение туннелей происходит на вашем марштрутизаторе) или ip адреса вашего российского vps (входной ноды вашего multi-hop прокси, на которой происходит разделение), после чего скомпрометированный сайт проверяет доступность “запрещённого” сервиса, запустив вредоносный код в вашем браузере. Таким образом, вы даёте скомпрометированному ресурсу узнать ваш российский ip (так или иначе привязанный к личности) и факт, что из вашего браузера доступны “запрещённые” ресурсы.

В современных браузерах существуют способы, позволяющие веб-приложению определить доступность удалённого ресурса в обход CORS. Вот минимальный сниппет, определяющий доступность телеграм из вашего браузера. Полагаю, подобные метрики будут в скором будущем внедрены на скомпрометированных веб-сайтах.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Telegram availability check</title>
</head>
  <body>
    <button id="check">Check telegram availability</button>
    <div id="result"></div>
    <script>
    function checkSiteAvailability(url, timeout = 5000) {
      return new Promise((resolve) => {
        const img = new Image();
        let resolved = false;
        const startTime = Date.now();

        const timeoutId = setTimeout(() => {
          if (!resolved) {
            resolved = true;
            resolve({
              available: false,
              error: 'Timeout'
            });
          }
        }, timeout);

        img.onload = () => {
          if (!resolved) {
            resolved = true;
            clearTimeout(timeoutId);
            resolve({
              available: true
            });
          }
        };

        img.onerror = () => {
          if (!resolved) {
            resolved = true;
            clearTimeout(timeoutId);
            resolve({
              available: false,
              error: 'Failed to load'
            });
          }
        };

        let cleanUrl = url.replace(/\/$/, '');
        img.src = `${cleanUrl}/favicon.ico?nocache=${Date.now()}`;
      });
    }

    async function checkTelegramAvailability() {
      const resultDiv = document.getElementById('result');

      const url = "https://web.telegram.org";

      resultDiv.innerHTML = `Trying ${url}...`;

      const result = await checkSiteAvailability(url);

      if (result.available) {
        resultDiv.innerHTML = `${url} is available. Are you using a proxy?`;
      } else {
        resultDiv.innerHTML = `${url} is not available. Error: ${result.error || "Unexpected"}`;
      }
    }

    document.getElementById('check').addEventListener('click', checkTelegramAvailability);
    </script>
</html>

Чтобы поиграться с примером локально, сохраните сниппет в index.html и запустите веб-сервер в той же директории, например python3 -m http.server 8080. Или просто откройте файл в браузере.

Факт доступности запрещённого ресурса с устройства пользователя сам собой не доказывает факта использования средств обхода блокировок, но, учитывая комплесный подход к определению недоброжелательных пользователей в методичке Минцифры, может быть учтён в дополнение к другим косвенным доказательствам использования средств обхода.

Насколько я вижу, единственный способ избежать такой атаки - это использование двух браузеров, одного тунеллированного напрямую, а другого через удалённый прокси, даже на десктопе. Трафик до российских сервисов для второго браузера должен быть закрыт (например, с помощью blackhole outbound в xray или blocked в sing-box), чтобы предотвратить случайный клик по ссылке на скомпрометированный сайт в проксированном браузере.

Пока нашел для себя самое банальное наколенное решение - поставить для госприложений режим “isolated“ в Rethink и руками разрешить им домены/ip которые им надо, чтобы работать. По крайней мере будет видно, когда они полезут не туда, куда раньше ходили…

P.S. .. и они туда не попадут

Лично я изначально избегал автоматических правил маршрутизации на уровне интерфейсов или устройств, поскольку это не очень надёжно и плохо предсказуемо. Мне проще руками, пусть с некоторым неудобством.

То есть я держу локальный сокс5, а нужные домены направляю в браузере правилами в Switchy Omega.

Насколько я читал, современные браузеры не позволяют из вне достучаться на локалхост без явного разрешения, то есть зашквар-сайты не должны кидать запрос через прокси.

Так?

Уже не раз показывали, что это не работает с большинством клиентов сейчас, приложения могут насильно слать запросы через интерфейс VPNа даже при их исключении.

Так зачем разрешать доступ к телеграм из браузера? Нужны дополнительные правила со связкой приложение плюс домены и ip. К телеграму доступ только из телеграма.

Можно вместо телеграма подключиться к серверу на любом из сотен миллионов заблокированных IP, со свежесозданным доменом, результат будет тот же.

Надо блокировать в браузере который ходит в впн все достаточно крупные российские сервисы, чтобы случайно на них не попасть, а попасть можно легко, их скрипты встроены наверно в 99% российских сайтов. Для них оставить отдельный браузер или отдельное устройство. И серфить осторожно, чтобы случайно не зайти на неизвестную ханипот страничку. В идеале с постоянно пополняемым белым списком доменов (все остальное в блок), но этим думаю еще рано заниматься.

Для чего городить эти сложные схемы, если достаточно маршрутизировать только заблокированные ресурсы с известными доменами и адресами? Пусть рф-сервисы ходят напрямую по умолчанию и ни о чем не подозревают.

Всякое шпионское (метрики и т.п.) по идее уже есть в списках адблоков.

Возможно здесь имеются ввиду смартфоны, на которых сложно делать маршрутизацию гибко. Поэтому делают per-app (даже на iOS).

На ПК да, лучше sing-box и либо только заблокированное (с учётом всех геоблоков), либо вообще всё и решать маршрутизацию на впс (включая блок ру-сервисов, если надо).