Туннели и VPN, устойчивые к DPI

Мы живем в интересное время. Я бы даже сказал, в удивительное. Кто-то из журналистов недавно назвал происходящее «цифровой гражданской войной». По одну сторону баррикад мы видим государство в лице госструктур, которое очень хочет знать, о чем между собой разговаривают его граждане, и очень хочет указывать им, что можно читать, а что нельзя, и в целях реализации своих желаний принимает различные законы и акты под надуманными предлогами. С другой стороны баррикад рядовые граждане, которые хотят отстоять свои права тайны личной переписки и свободного получения информации, и не хотят, чтобы факты этой самой переписки и получения этой самой информации были использованы против них. Бонусом проблемы огребает различный бизнес и IT-отрасль в целом.
Но нет, эта статья не о политике, а о технологиях.

image


Техническая грамотность людей, благодаря всему происходящему, тоже растет. Если раньше слова «VPN» и «прокси» были знакомы только IT-специалистам, то теперь даже домохозяйки их знают, и более того — используют то, что эти слова означают.
Должностные лица, правда, тоже не дремлют. Новости приходят весьма занятные. Например, предоставление услуг VPN и аналогичных для шифрования трафика и обхода блокировок ныне наказуемо, а в Китае так за это вообще сажают в тюрьму. А не так давно РКН начал применять анализ пакетов для блокировки протокола MTProxy. Можно также обратиться к опыту наших стран-собратьев, которые наиболее преуспели в таких делах: Китая, Ирана, Казахстана, Венесуэлы. В Венесуэле, например, вполне конкретно блокируют прямые подключения к Tor и обфусцированный трафик к мостам. Исходя из всего этого, можно предположить, что будущее ждет нас тоже очень интересное, особенно, если РКН перестанет устраивать тупые факапы раз за разом, а будет действовать умнее и изощреннее.

На Хабре неоднократно в комментариях озвучивали прогнозы как дальше государство может бороться с технологиями шифрования для обычных граждан. Анализируя озвученные мысли и посмотрев на свидетельства из других стран, я попробовал предположить, в какую сторону могут дальше двинуться меры по ограничению связи. DistortNeo и shifttstas подкинули еще несколько интересных идей, и в итоге я пообещал el777 все-таки дописать эту статью.
С фильтрами по ACL всё в целом ясно. Они действуют уже сейчас, и с ними с переменным успехом получается и не получается бороться (хотя существуют вполне себе пессимистические прогнозы). С DPI все интереснее. Способы «определения» типа трафика у DPI можно разбить на две группы:

  • Сигнатурный анализ. А именно, разбирание пакета «по косточкам», сопоставляя заголовки и структуру с образцами, и таким образом определение его предназначения. Таким образом детектируются многие туннели, например OpenVPN, L2TP/IPSec, SOCKS, и др.
  • Предварительный анализ паттернов обмена трафиком, например, соотношения входящего/исходящего потока, периодичность запросов-ответов и другие критерии позволят отделить «настоящий трафик» какого-то протокола и туннель, лишь маскирующийся под него.

image

Можно разбить трафик на несколько групп и предположить, что будут делать с каждой из них.
1. «Явные» VPN, туннели и прокси (OpenVPN, L2TP/IPSec, SOCKS, и др.) Вполне могут блокироваться автоматически, как, например, это происходит в Китае и Венесуэле. Если каким-то организациям или компаниям оно нужно для работы — пусть регистрируются и сертифицируются, о чем вполне конкретно говорит российский закон, упомянутый выше.
2. Технологии «двойного назначения», например, SSH. Через небольшое время после установления сессии, скорость режется до черепашьей, так, что в консоли работать еще хоть как-то можно, а вот серфить и качать что-либо уже нет. То, что это создает проблемы при обычной работе, никого не волнует (что не раз нам демонстрировал РКН за недавнее время).
3. Узкоспецифические протоколы, типа месседжеров, игровых клиентов, и т.д.
4. Соединения, тип которых определить не удается.
Для пунктов 3 и 4 вполне возможны «белые списки» (в которые, например, заносятся подсети официальных игровых серверов или «правильных» месседжеров, и всего того, что владельцы серверов пожелают задекларировать и оформить как надо, чтобы их не трогали). А тех, кого в этих списках нет, ждет та же участь, что и п.1 или п.2, правда вполне возможна не тупая блокировка или обрезание скорости, а предварительно упомянутый выше анализ паттернов обмена в целях определения, является ли трафик «чистым» или «подозрительным».
То есть, при желании маскироваться под специальные протоколы, или же обфусцировать соединения, чтобы было невозможно определить их тип, придется так же позаботиться о создании «шума», препятствующего выявлению реально паттернов обмена. Пока что подобных разработок мне на глаза не попадалось.
Про разные ICMP и DNS туннели можно даже не вспоминать — большой объем трафика «куда не надо» по ним тоже автоматически вызывает подозрения.
5. TLS и SSL, HTTPS. Резать подчистую невозможно, поскольку это автоматически означает блокировку всего Интернета. Анализ паттернов не имеет смысла, поскольку веб-серфинг — как раз-таки и есть основное предназначение использование HTTPS. Из всего вышеперечисленного, SSL/TLS на 443 порту выглядит самым «не подозрительным» и надежным вариантом. Следовательно, давайте и попробуем замаскироваться под него.

image

Маскируемся


Для рассмотрения было решено выбрать решения Streisand и SoftEther.
Streisand — целый набор различных сервисов: OpenConnect/AnyConnect, OpenVPN, stunnel, Shadowsocks, WireGuard. Все это ставится в автоматическом или полуавтоматическом режиме «под ключ», и на выходе пользователь получает сконфигурированный сервер, а также файлы и подробную документацию по настройке клиентов.
SoftEther — VPN-сервер, который может поднимать L2TP/IPsec, OpenVPN, SSTP, и другие протоколы, а также имеет свой собственный протокол «SSL-VPN», который, по заявлениям авторов, неотличим от обычного HTTPS-трафика.

Итак…

OpenConnect/AnyConnect. Опенсорсная реализация протокола AnyConnect SSL от Cisco. При установлении соединения видны не только пакеты TLS (TCP), но и DTLS (UDP). DTLS в принципе тоже много где используется «в мирных целях», но это уже совсем не похоже на «обычный HTTPS».

Shadowsocks. Шифрованный SOCKS-прокси. Судя по всему, при желании может быть детектирован, однако существуют плагины, маскирующие его под «чистый HTTPS».

WireGuard. Судя по описанию, имеет хорошо закрученное шифрование и механизм установки сессии, но весь обмен происходит по UDP. Wireshark определяет тип пакетов как нечто совсем невнятное, а какое мнение обо всем происходящем сложится у стороннего DPI — очень и очень большой вопрос.

obfs3, obfs4. Обфуцируют пакеты так, что со стороны они выглядят абсолютно случайным набором значений. То есть попадают под п.4 из списка выше.

SoftEther. Выглядит как HTTPS, но с одним подвохом. Кроме непосредственно TLS over TCP активно шлет пачками UDP-пакеты. Как удалось выяснить в документации, UDP может использоваться используется для ускорения передачи данных, в том случае, когда он не зарезал на фаерволе. Данный функционал отключается в конфигурации, и после его отключения все становится как надо.

SSTP. VPN-прокотол от компании Microsoft. Нативно поддерживается в Windows, вспомогательным софтом в GNU/Linux. Со стороны выглядит как HTTPS, и Wireshark это вполне подтверждает.

Но это еще не все


Предположим, вы установили на хост VPN-сервер или конец туннеля и сконфигурировали, чтобы он слушал 443 порт. Казалось бы, все прекрасно, но есть одно НО: если мы маскируемся под HTTPS, проверить, что по факту висит на 443 порту можно просто попробовав уткнуться в этот порт простым браузером или CURL’ом, или еще каким угодно способом. В некоторых статьях подобный метод называется «опережающим подключением», и, как упоминается, уже вполне используется в Китае.
Следовательно, нам необходимо чтобы по 443 порту у нас отвечал самый обычный и порядочный веб-сервер. И вот тут встает интересная проблема.
Ни у одного из вышеперечисленных сервисов в основной документации не нашлось описания рабочего механизма port sharing’а. Вариант с SSLH не подходит, хотя бы потому, что sslh не способен разделить трафик между HTTPS и вышеуказанными сервисами. Как минимум, потому что если тип трафика без полной расшифровки смог отличить sslh — то сможет и DPI.
Большинство манов, наподобие этого, предлагают использовать Server Name Indication (SNI) — расширение TLS, позволяющее указывать имя хоста, и потом с помощью HAProxy, sniproxy и других тулов раскидывать подключения по сервисам. Проблема в том, что указанное при использовании SNI имя хоста передается plain text’ом, то есть в незашифрованном виде, и, следовательно, тоже может быть подсмотрено и использовано в дальнейшем.

Поэтому, будем импровизировать, и тут мне на ум пришли два варианта.

Port knocking

image

Port knocking как раз предназначен для активации «скрытых сервисов» на сервере. В классическом варианте (см. например реализацию демона knockd) под нокингом обычно понимают попытки установки соединения или посылку пакетов на определенные порты хоста в определенной последовательности, в результате чего демон вас «опознает» как своего, и активирует правило фаерволла, открывающее доступ на определенный порт только с вашего IP.
В нашем же случае, этот вариант не совсем приемлем. Во-первых, сами «нестандартные» порты могут быть заблокированы где-то по пути, а во-вторых, сама процедура при анализе со стороны может выглядеть подозрительно. Раз уж мы маскируемся под HTTPS, то и «стучаться» нужно по HTTPS.

Как ни удивительно, но HTTP/HTTPS нокеров с требуемой функциональностью я не нашел, и поэтому на свет родился нокер с романтичным названием Labean, который я набросал за пару обеденных перерывов в кафешке неподалеку от офиса.

Дано: наш сервер, на котором на 443 порту крутится Nginx c корректно настроенными сертификатами и выдает какой-нибудь вполне безобидный контент, например, GIF’ки с котиками, ISO-образы дистрибутивов GNU/Linux, или зеркало Википедии и библиотеки Машкова.
При этом в конфиге Nginx затаились строки вида

 location ~ ^/somesecret/(.*) {
    auth_basic      "Administrator Login";
    auth_basic_user_file  /var/www/.htpasswd;
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_pass http://127.0.0.1:8080/$1;
  }

Когда мы хотим подключиться к скрытому сервису, мы переходим браузером или делаем запрос CURL’ом по адресу вида
https://ourserver.org/somesecret/vpn/on
проходим стандартную авторизацию, после чего нокер, получив и обработав наш запрос, выполнит команду на открытие доступа к скрытому сервису для нашего IP-адреса, например что-то вроде
iptables -t nat -A PREROUTING -p tcp -s {clientIP} --dport 443 -j REDIRECT --to-port 4443
после чего мы поднимаем туннель.

Далее через N секунд (да, поддерживается автоматический таймаут) выполняется команда, отменяющая вышеуказанное правило фаервола, и таким образом наше установленное подключение остается висеть, но подключиться к сервису снова даже с нашего IP без повторного дерганья нокера уже не выйдет.
Либо можно не использовать автоматический таймаут, а вручную деактивировать сервис, запросив URL наподобие указанного выше, только с /off в конце.
Таким образом можно сконфигурировать даже несколько разных сервисов, в том числе используя IPv6 (v6-адреса в заголовке типа X-Real-IP также поддерживаются).

Нокер написан на Go, не требует внешних зависимостей, прост как топор, и вполне себе работает. Исходники, подробное описание и примеры конфига nginx и init-скриптов можно найти на Gihub:
https://github.com/uprt/labean
Буду признателен за багрепорты, пулл-реквесты, гитхаб-звездочки и вообще любые хорошие идеи и предложения.

Websockets

image

Вторая идея озарила еще более неожиданно: лучшее средство замаскировать туннель внутри HTTPS — использовать общепринятые стандартные средства. Современные Web-технологии давно уже содержат решение для установления связи поверх TCP между браузером и сервером, и имя ему Websocket (RFC 6455). Клиент формирует особый HTTP-запрос, на который сервер отвечает определенным образом, и после небольшого хендшейка мы можем начинать передачу данных по этому же TCP-соединению. Со стороны, соответственно, все выглядит в точности как обычный HTTPS и не требуется установки никаких дополнительных соединений.
Реализаций WS-туннелей существует несколько (есть даже вариант на Haskell), я для теста взял wstunnel, написанный на NodeJS и не прогадал, все завелось легко и с первого раза.
Лишь один нюанс был не прояснен в документации. Для запуска клиента предлагается указывать просто wss://-адрес, типа

wstunnel -t 33 wss://server:443


В нашем же случае, необходимо «отделить» ws-подключения к серверу туннелирования от запросов «обычного» сайта. Изучив исходники wstunnel, я пришел к выводу, что ничего не помешает удлинить URI после имени хоста каким-нибудь уникальным идентификатором:

wstunnel -t 33 wss://ourserver.org:443/hiddenws/


и оказался прав: все заработало с первого раза

Снова рассмотрим наш сервер, на котором на 443 порту запущен Nginx c каким-нибудь безобидным сайтом.
В конфиг нужно добавить proxy-проброс для нашего Websockets-туннеля:

location /hiddenws {
    proxy_pass http://127.0.0.1:8081;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
  }


После чего мы можем тайным образом поднимать наш websockets-туннель. Поверх туннеля можно пустить подключение к обычному SOCKS-прокси (например, Dante), или OpenVPN, хотя, как по мне, это уже будет избыточно.
Единственный минус такого подхода — кроме непосредственно SOCKS- или VPN-клиента на устройстве также нужно иметь клиент wstunnel, что может быть сложным в случае использования смартфона или другого «недесктопного» устройства.

Вместо заключения


image
Как на самом деле будет развиваться социально-техническое противостояние, мы знать не можем — только предполагать. Воплотятся ли в жизнь предположения, изложенные в статье, не воплотятся — узнаем со временем, как и о том, что будет дальше. Да, маскировка под HTTPS тоже не панацея от всего — например, делать это может быть опасно, если на будет введено административное или уголовное наказание за «использование несертифицированных средств шифрования»/ознакомление с запрещенными ресурсами/etc., или бесполезно, если на государственном уровне всех обяжут устанавливать «национальный сертификат безопасности», как это некоторое время назад хотели сделать в Казахстане.
Пока еще, к счастью, ни до того, ни до другого не дошло ни одно из известных нам государств, и если оно случится — это знак, что пора эвакуироваться, причем не из страны, а с планеты.
Берегите себя.

© Habrahabr.ru