Mullvad exit IPs are surprisingly identifying

15.05.2026 · 5 мин

Меня всегда забавляет, когда VPN-сервисы (Virtual Private Network — защищённое соединение, которое маскирует ваш реальный адрес в интернете) обещают полную анонимность. Типа «ваш IP (уникальный номер устройства в интернете, как почтовый адрес для компьютера) скрыт, вы в безопасности». Но реальность обычно сложнее. Недавно наткнулся на исследование, которое заставило меня по-другому посмотреть на Mullvad — казалось бы, один из самых приватных VPN на рынке.

Суть в том, что IP-адреса выхода (те, которые видят сайты) не такие уж случайные, как кажется. И это может выдать вас с головой.

Как работает Mullvad

Для тех кто не в курсе: Mullvad — это шведский VPN-провайдер, который делает упор на приватность. Никаких логинов, никакой подписки через email — просто сгенерировал аккаунт и пользуешься. Приятно.

У них около 578 серверов — это скромно по меркам Proton VPN с его 20 000. Но есть фишка: на каждом сервере много IP-адресов для выхода. Когда два человека коннектятся к одному серверу, они обычно получают разные публичные IP. Это нужно, чтобы не попасть под блокировку сайтов, которые не любят, когда с одного IP сидит тысяча человек.

Но вот что интересно: IP назначается не случайно при каждом подключении. Он выбирается на основе вашего WireGuard-ключа (современный протокол VPN — способ шифрования трафика). Точнее, на основе публичного ключа (pubkey — публичный ключ, уникальный идентификатор вашего VPN-соединения, как отпечаток пальца). Этот ключ меняется каждые 1-30 дней (или вообще никогда, если используете сторонний клиент).

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

Эксперимент

Автор написал скрипт, который менял pubkey и собирал IP-выбора для 9 серверов. За ночь накопились данные для 3650 ключей — достаточно, чтобы понять картину.

Вот что показали серверы:

СЕРВЕР               ДИАПАЗОН IP              # АДРЕСОВ
─────────────────────────────────────────────────────────
au-syd-wg-101        103.136.147.5 - .64       60
cl-scl-wg-001        149.88.104.4 - .14        11
de-ber-wg-007        193.32.248.245 - .252      8
dk-cph-wg-002        45.129.56.196 - .226      31
fi-hel-wg-201        185.65.133.10 - .75       66
us-lax-wg-001        23.234.72.36 - .126       91
us-nyc-wg-602        146.70.168.132 - .190     59
us-sjc-wg-302        142.147.89.212 - .224     13
za-jnb-wg-002        154.47.30.145 - .155      11
Пул IP-адресов для каждого сервера

Если посчитать общее количество комбинаций для этих девяти серверов, получается больше 8 триллионов. Огромное число. Должно быть достаточно, чтобы каждый ключ получал уникальную комбинацию IP.

Но вот подвох: из 3650 протестированных ключей получили только 284 уникальные комбинации. 284! Это капля в море по сравнению с триллионами.

Разгадка

Автор заметил закономерность: если взять позицию IP внутри пула и поделить на размер пула, получается примерно одинаковое число для всех серверов.

Например, для комбинации, которую он отслеживал:

СЕРВЕР               ПОЗИЦИЯ   РАЗМЕР ПУЛА  ПРОЦЕНТИЛЬ
──────────────────────────────────────────────────────
au-syd-wg-101        49        60            81.6%
cl-scl-wg-001        9         11            81.8%
de-ber-wg-007        7         8             87.5%
dk-cph-wg-002        25        31            80.6%
fi-hel-wg-201        54        66            81.8%
us-lax-wg-001        74        91            81.3%
us-nyc-wg-602        48        59            81.4%
us-sjc-wg-302        11        13            84.6%
za-jnb-wg-002        9         11            81.8%
Все IP попадают примерно в 81-й процентиль (значение, ниже которого находится определённый процент всех данных — как если бы вы сказали: «80% людей тратят меньше 10000 рублей»)

Все они где-то в районе 81%. Это не совпадение.

Автор предположил, и это очень похоже на правду: Mullvad использует генератор случайных чисел (RNG — генератор случайных чисел, программа, которая «бросает кубик») с затравкой (seed — затравочное число, начальная точка, от которой зависит вся последовательность «случайных» чисел) на основе pubkey. То есть ключ определяет начальное число для генератора, а дальше он выбирает позицию IP в пуле.

Но вот проблема: в Rust (а Mullvad написан на Rust) функция random_range (функция в языке Rust, команда для получения случайного числа в заданном диапазоне) работает так, что само число с плавающей точкой генерируется один раз из затравки, а потом просто умножается на размер пула. То есть границы (bound) не влияют на энтропию (мера непредсказуемости — чем выше энтропия, тем сложнее угадать результат) — они просто масштабируют уже сгенерированное число.

Это как если бы вы бросали кубик один раз, а потом просто умножали результат на любое число, какое вам скажут. Кубик выдал 0.5, вы умножаете на 60 — получаете 30. Меняете пул на 100 — получаете 50. Один и тот же «кубик», разные множители.

Отсюда и 284 комбинации вместо триллионов. Все IP привязаны к одному и тому же диапазону процентилей.

Что это значит на практике

Автор сделал инструмент, который по набору IP может оценить, сколько пользователей Mullvad имеют такую же комбинацию. Возьмём пример из статьи: определённый набор IP соответствует диапазону чисел от 0.2909 до 0.2943. Это 0,34% от всех пользователей.

При 100 000 активных пользователей Mullvad — примерно 340 человек имеют такую же комбинацию IP. Не уникально, но и не случайно.

Теперь представьте модератора на форуме. Приходит новый пользователь, которого подозревают в том, что это клон заблокированного. Оба используют разные серверы Mullvad, но оба попадают в пересекающиеся диапазоны: 0.4334-0.4428 и 0.4358-0.4423. Пересечение даёт вероятность больше 99%, что это один и тот же человек.

Звучит как научная фантастика? Но теперь добавьте сюда утечки данных и запросы через правоохранительные органы. IP-логи есть у всех. Если кто-то получит доступ к логам с разных форумов или сервисов, он может коррелировать эти данные и вычислить, что за человек сидит за Mullvad.

Как защититься

Автор даёт несколько советов:

  1. Не переключайте серверы чаще одного раза за период жизни ключа. Каждое переключение — это новый набор IP, который можно отследить.
  1. Принудительно ротируйте ключ. В приложении Mullvad можно «выйти», что сгенерирует новый ключ.

Это не идеальная защита, но хотя бы что-то.

Что я думаю

Меня зацепило вот что: это не уязвимость в коде шифрования, а логическая ошибка в алгоритме выбора IP. Разработчики, вероятно, думали, что random_range каждый раз пересчитывает случайное число — и не учли, как работает Rust.

Вывод для меня простой: никакой VPN не даёт 100% анонимности. Всегда есть вектор атаки. Даже если вы доверяете сервису — доверяйте его коду, его реализации. Используйте дополнительные меры (ротация ключей, смена серверов) и не верьте маркетингу. И помните: если вы параноик, это не значит, что за вами не следят.

Ссылки

Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.