Давайте сразу вопрос на засыпку: может ли быть так, что клиент подключается, ну, например, к серверу www.python.org (самому настоящему, тому, к которому обращаются еще миллионы клиентов со всего мира), а потом использует его как прокси и гоняет через это подключение трафик до своего VPS для доступа в неподцензурный интернет? Если вы не уверены в ответе на этот вопрос или почему-то ответили "нет", то добро пожаловать в статью.

Я уже не раз рассказывал здесь о технологии XTLS-Reality (1, 2, 3), суть которой в том, что ваш прокси-сервер VPS может очень достоверно маскироваться под какой-нибудь популярный веб-сайт — принимать подключения, которые будут выглядеть точно так же, как обращения к настоящему сайту, отвечать на них полностью аутентичным TLS-сертификатом, и в целом вести себя как тот настоящий сайт. Сервер проверяет специальную магию в запросе при установлении TLS-соединения (которую невозможно выявить, точно не зная что она там есть и не зная секретные ключи), и если проверка прошла успешно, то работает как прокси, а если нет — то передает запросы на настоящий сервер, а потом передает ответы от него. Единственная проблема — сам IP-адрес. Немного подозрительно, когда к какому-нибудь якобы www.google.com постоянно обращается только один пользователь, а IP-адрес этого сервера на самом деле даже не относится к автономной сети Google.

Еще я рассказывал о разных вариантах проксировать трафик посредством вебсокетов и простых HTTP-туннелей через различные CDN, такие как Cloudflare и Gcore. Вероятность того, что под блокировку попадет вся CDN гораздо ниже, чем что забанят какой-то один сервер или диапазон хостера, но та схема требовала регистрацию своего домена для работы через CDN.

И наверняка многим в голову приходила идея, а нельзя ли как-нибудь совместить эти два механизма? Проксироваться через CDN, но при этом "прикрываясь" каким-нибудь чужим доменом? Ответ: да, можно, и сейчас мы посмотрим, как именно.

Итак, что такое "domain fronting"?

Что такое CDN, вы, наверное, хорошо знаете: это сети из тысяч серверов, которыми оперируют компании типа Cloudflare, Google, Amazon, и т.д, нередко с выделеными каналами связи между ними, которые используются для доставки интернет-трафика клиентам. Благодаря оптимальным маршрутам следования трафика и кэшированию данных поближе к пользователям, они позволяют раздавать контент быстрее и эффективнее и гибко масштабировать нагрузку.

А теперь разберем, что именно происходит, когда вы подключаетесь браузером к какому-нибудь сайту по HTTPS. Первый шаг - установление зашифрованного соединения по протоколу TLS. В самом начале запроса клиент, среди других данных, передает на сервер строку, называемую SNI - server name identification, в которой он указывает, к какому именно домену он хочет подключиться (потому что один веб-сервер может обслуживать сразу много доменов). Эта информация передается в нешифрованном виде, ее могут прочитать цензоры и заблокировать ваше подключение, если им не понравился домен интересующего вас сайта. Второй шаг — когда шифрованное подключение уже установлено, начинает работать протокол HTTP, и там, в заголовках запросов, есть поле "Host", в котором снова указывается домен сайта, к которому вы обращаетесь. На этом этапе данные передаются уже в зашифрованном виде, и подслушать со стороны их нельзя. Когда вы серфите сайтом в браузере, эти два значения (SNI в TLS и Host в HTTP) всегда одинаковые.

И когда-то очень давно, какой-то сообразительный хакер подумал: CDN может обслуживать сотни и тысячи разных сайтов, а что если мы передадим в SNI домен одного сайта, а в Host - домен другого? Он (или она, кто ж знает) попробовал и с удивлением обнаружил, что все работает и так - сервер демонстрирует TLS-сертификат домена, который был запрошен в SNI, но при этом отдает содержимое веб-сайта для другого домена, который был запрошен в HTTP Host. Так и появился domain fronting - когда обращаясь к веб-серверу мы "снаружи" демонстрируем один домен (приличный, разрешенный, незаблокированный), а на самом деле нас интересует другой.

Я, пожалуй, разделил бы domain fronting на два типа.
Первый тип - это когда мы прикрываемся каким-нибудь популярным доменом на той же CDN. Понятное дело, что для этого надо, чтобы CDN такое позволяла, а таких CDN все меньше и меньше - потому что кроме нас таких хороших подобной техникой еще пользуются всякие жулики для вредоносного ПО.
Второй тип - это когда CDN не разрешает прикрываться чужим доменом, но при этом для целей раздачи контента выдает свой технический домен типа cdn-abg456sf1.bignetwork.com, и мы можем работать через него, что тоже неплохо - во-первых не нужно иметь свой домен, а во-вторых, подобные домены все равно очень популярны, используются на тысячах сайтов, и ведут в правильный IP-диапазон, принадлежащий этой CDN. А если вдруг домен попал под блокировку, перепрыгнуть на другой можно за пару минут.

Осталось только узнать, какие именно CDN такое разрешают. Обладая эти знанием, мы можем гонять трафик до прокси-сервера через CDN, прикрываясь каким-нибудь чужим популярным доменом, например, через вебсокеты средствами XRay или GOST, или даже без веб-сокетов (если CDN их не поддерживает или хочет за них дополнительных денег) через plain HTTP tunnel. Такую же механику использовал популярный мессенджер Signal, пока их не выгнали с Google Cloud и с Amazon, такую же механику до сих пор использует Tor с транспортом meek.

Собственно, в wiki Tor есть очень и очень интересный документ: https://gitlab.torproject.org/legacy/trac/-/wikis/doc/meek. Там разбирается механика domain fronting, и приведен анализ возможностей использования его на разных популярных CDN. Одно НО — документ датируется 2018-м годом, и с тех пор очень многое поменялось. Я советую все равно изучить его для вдохновения и идей, а пока поделюсь тем, что успел нарыть сам.

Серверную часть можно настраивать так, как я описывал в статье "Особенности проксирования через CDN/Websocket/gRPC для обхода блокировок", разве что в некоторых случаях вместо TLS (HTTPS) на сервере понадобится обычный HTTP (без шифрования и сертификатов). Также возможно использовать на сервере GOST и его родной клиент.

Fastly

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

При регистрации дарят 50 долларов на аккаунт. Никаких паспортных данных предоставлять не надо, банковскую карту привязывать тоже, поэтому, в теории, ни что не мешает создавать новый аккаунт каждый раз, когда закончилась халява на старом (если что, осуждаем). Fastly может проксировать вебсокеты, они там идут по отдельному тарифу, но есть бесплатный 30-дневный пробный период.

Чтобы создать ресурс, нужно зарегистрироваться, потом пойти в раздел "Deliver", нажать "Create delivery service". Если у вас нет своего домена или вы не планируете его использовать, то в "Domains" можно написать все что угодно:

Далее идем в Origins -> Hosts и добавляем IP-адрес вашего сервера:

После добавления Origin Host можно нажать на редактирование и посмотреть, что там еще есть, а именно, настройки TLS:

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

Но тут есть важный нюанс, в документации Fastly про проксирование вебсокетов написано, что вебсокеты не будут работать с самоподписанными сертификатами. Что там говорить, у меня они даже с настоящим сертификатом от LetsEncrypt не заработали, пока я не отключил TLS вообще. Поэтому можно оставить "No, do not enable TLS" и CDN будет подключаться к вашему серверу на простой 80 порт без шифрования.

В принципе, если вы хотите использовать plain HTTP tunnel, то это достаточно - можно сохранять параметры, нажимать "Activate", подождать 5-10 минут, пока информация о вашем ресурсе разлетится по серверам сети Fastly, и можно начинать пользоваться.

Если же вы хотите использовать вебсокеты, то все чуть сложнее - идем слева в меню в Settings -> Webosckets, скроллим вниз, активируем триальный период для вебсокетов и сами вебсокеты:

Думаете все? Ха, хрен там. Нужно сделать еще одну очень неочевидную вещь, которая запрятана глубоко в документации: https://developer.fastly.com/learning/concepts/real-time-messaging/websockets-tunnel/

Идите слева в меню в VCL snippets, нажмите Create your first snippet:

Там задаете какое-нибудь имя, выбираете средний тип "within subroutine", и саму сабрутину recv (vcl_recv), и вставляете там такой код:

 if (req.http.Upgrade) {
   return (upgrade);
 }

Сохраняете, и наконец-то делаете Activate для вашего ресурса. Ждете 5-10 минут (раньше бесполезно - не заработает) и можно пробовать.

Настраивайте свой прокси-клиент с вебсокетами или plain HTTP tunnel так, чтобы он стучался на адрес какой-нибудь популярного сайта, который испольщует Fastly, например, www.python.org или www.spotify.com, пусть в SNI передается тоже www.python.org или www.spotify.com, но при этом в поле "Host" HTTP-запроса должен быть ваш домен (возможно даже в реальности не существующий), который вы указали при создании ресурса в Fastly.

Пример настройки вебсокетов в Nekoray через Fastly и domain fronting, при условии, что у вас на сервере XRay или Sing-box с настроенными вебсокетами

Amazon Cloudfront

Здесь у нас будет возможен фронтинг типа 2 - Amazon выдает "технический домен" для раздачи контента.

В первую очередь надо зарегистрироваться в облаке Amazon. Хоть мы и будем использовать Free Tier, придется привязать банковскую карточку, и да, карты российских банков не принимаются.

у меня вообще была совершенно фееричная история с регистрацией

Я зарегистрировался в Amazon Cloud, но при попытке создать новый ресурс в Cloudfront вылетало сообщение типа "Неизвестная ошибка, обратитесь в техподдержку" (да, для тех кто делает такие сообщения об ошибках в аду зарезервирован отдельный котел). Я начал переписку с техподдержкой (на первой линии у них, кажется, отвечает нейросеть), и в итоге выяснилось, что им "требуется дополнительная верификация моего аккаунта". Впрочем, это не удивительно - у меня давным-давно был аккаунт со страной Russia, теперь у меня новый аккаунт с телефоном и адресом страны, где я теперь живу, но с тем же ФИО, при этом IP-адреса моего провайдера почему-то во всех GeoIP-база определяются не как страна где я живу, а как Германия, а карточку я привязал банка Revolut, которая по коду платежной системы вообще относится к какому-то литовскому банку. Короче, очень подозрительный аккаунт получился :)

В процессе переписки с саппортом мне вообще закрыли доступ к аккаунту. Оказалось, что Amazon несколько раз мне присылал емайлы, типа, "нам нужно уточнить ваши данные, пожалуйста, загрузите вот по этой ссылке вот такие документы в течении 3-х дней", но при этом GMail почему-то такие письма от Amazon'а отмечал как опасные и фишинговые (!) и отправлял сразу в спам, где я их, естественно, не видел.

В итоге они потребовали отправить им какие-нибудь счета за коммунальные услуги, где видно мое имя и адрес, а так же выписку из банка для карты, которую я привязал. Тут я немного подофигел, потому что жилье я арендую и счета приходят не на мое имя - в итоге сошлись на том, что я пришлю им ежемесячную квитанцию от моего мобильного оператора (там есть мое имя и адрес), и выписку со счета Revolut'а. После загрузки документов они присылали мне ответ, что мои документы "неразборчивые", не указывая, что именно там черт возьми неразборчивое, я загружал их снова, в итоге на 4-ую или 5-ую итерацию они все-таки согласились, что да, документы разборчивые :) Возможно помогло приложенное сопроводительное письмо, мол "вот это и вот это - вот это, и обратите внимание, dear sir or madam, выписка из банка - по счету, но если вы присмотритесь, то в деталях транзакции увидите так желаемый вами номер карты". И да, еще важно, чтобы выписка была именно по тому счету, с которого Амазон списал и вернул 1 евро для верификации карты.

В итоге аккаунт мне разблокировали, я попробовал снова создать ресурс в Cloudfront, и... снова получил ту же самую ошибку. Я переоткрыл тикет в поддержке, написал что проблема решена и изложил все что думаю по поводу их саппорта и сервиса. В итоге в субботу утром (!) мне поступил звонок на телефон с нью-йоркского номера, голос на другой стороне на хорошем английском представился саппортом Амазона, попросил продиктовать код верификации, который они отправили на емайл (там в емайле прямо так и пишется, "for Your Recent Support Request" и "please provide the following One-Time-Password (OTP) over the phone"), после чего сообщил, что они моё обращение разобрали, что-то там поправили у себя в моем аккаунте, и попросили сразу проверить, что теперь все работает. Я проверил - действительно заработало.

Итак, создали аккаунт, выбираем Free Tier - он включает в себя бесплатно 1 терабайт передаваемых данных в месяц и 10 миллионов запросов. С запросами аккуратнее, при постоянном использовании Plain HTTP tunnel их можно высадить и раньше чем за месяц, но мы будем использовать вебсокеты, Amazon их поддерживает даже на бесплатном тарифе.

Идем в консоли в Cloudfront, нажимаем Create distirbution:

И начинаем заполнять. Придется иметь свой домен, хоть какой-нибудь, пусть даже это будет бесплатный DynDNS - только лишь IP-адрес система использовать не дает. Вставляем его в Origin domain.
Протокол я для простоты выбрал HTTP only, чтобы не заморачиваться с сертификатом на сервере.

Далее привожу настройки, которые сработали у меня:

Origin shield = No

Viewer protocol policy = HTTP and HTTPS

Allowed HTTP methods - не особо важно, но на всякий случай выберем все

А вот теперь важное. Cache policy = caching disabled, Origin request policy = AllViewer - это нужно чтобы CDN передавала все заголовки от клиента на ваш сервер, иначе не заработают вебсокеты.

Web Application Firewall - я отключил.

Готово, нажимаем "Create distribution", и через некоторое время Cloudfront покажет вам ваш новый ресурс и технический домен для него:

Подождите, пока в поле Last modified появится нормальная дата, а не сообщение о том, что данные распространяются на сервера Cloudfront - до этого момента домен возможно уже будет работать, но вебсокеты не заведутся. Не лишним будет еще подождать 5-10 минут для надежности.

Все, а теперь вы можете использовать ваш технический домен *.cloudfront.net из поля "Distribution domain name" слева для подключения к своему прокси через вебсокеты. Все три параметра (адрес сервера, SNI и поле host) должны указывать на этот ваш домен.

пример настройки вебсокетов в Nekoray с Amazon Cloudfront, при условии, что у вас на сервере XRay или Sing-box с настроенными вебсокетами

Что еще?

А остальное - это ваше домашнее задание :) Существует еще много разных CDN - Microsoft Azure, Akamai, CDNetworks, Edgio, Stackpath, Level3 (его реселлеры VPS.NET и CloudVPS), Melbicom, CDN77, EdgeCast, и другие.

Допускают ли они domain fronting или предоставляют ли хотя бы технические домены - нам еще предстоит проверить. Я предлагаю поучаствовать в этом и вам по мере возможностей (да, могут потребоваться небольшие денежные вложения) и делиться результатами в комментариях к этому посту или на форуме ntc.party.

Ну а еще что?

Транспорт meek от Tor имеет интересную возможность работать через так называемые "рефлекторы" - когда для того, чтобы подключиться к вашему прокси, используется не CDN, а простой скрипт на PHP или Python, который просто 1-в-1 передает пришедшие на него запросы на ваш прокси и обратно. Такой скрипт можно разместить даже на дешевом тупом shared-хостинге (не VPS), и гонять трафик через него. Зачем? Есть теория, что некоторые shared-хостинги тоже допускают domain fronting - например, судя по всему, что-то такое умеет HostGator, а возможно и многие другие.

Meek является pluggable transport'ом Tor, поэтому его непросто заставить работать отдельно (возможно поможет ptadapter - если кто-то разберется, как заставить его работать с meek, напишите пожалуйста статью или хотя бы мне в ЛС), однако, судя по всему, довольно легко адаптировать его PHP-рефлектор для работы с plain-HTTP-tunnel из GOST, а может быть он заработает даже без переделки. Что открывает очередной простор для экспериментов :)

Важно: автор не присутствует в Telegram или каких-либо иных месседжерах или соцсетях, не оказывает никаких платных консультаций и не выполняет никаких работ за деньги, а на вопросы отвечает только на Хабре (когда есть время). Остерегайтесь мошенников.

P.S. Если есть желание сказать автору спасибо за все его труды и бессонные ночи — то:
USDT (TRC20) TQBBP7fSex6Vh9rVVNBYN5ZiLgbuVFrYgp
BTC bc1qvfm3y658248adptju7x6xjjq0mv3gj6pa334z4

Комментарии (20)


  1. Fleym
    03.12.2023 13:43
    +5

    Это мы сохраняем… В PDF, и сразу на ЖД и по облакам.


  1. olegtsss
    03.12.2023 13:43

    В tls 1.3 разве не была реализована передача SNI после установления шифрования (ведь как раз dpi может читать SNI, но не может читать установленное http соединение)?


    1. MiraclePtr Автор
      03.12.2023 13:43
      +3

      В TLS 1.3 - нет, Encrypted Client Hello не вошёл в стандарт.

      Это отдельное пока ещё не везде поддерживаемое расширение, и в Китае, например, такие подключения начали блокировать ещё несколько лет назад (когда оно ещё называлось eSNI).


      1. olegtsss
        03.12.2023 13:43

        Забавно идет развитие. Придумаешь новое техническое решение, его запрещают (блокируют). Думаешь дальше, как пробить). Хотя стагнацией - это тоже не назовешь.


        1. MiraclePtr Автор
          03.12.2023 13:43

          Вечная битва щита и меча, да. Что интересно, чем более сложные методы применяет одна сторона, тем более сложные (а следовательно, дорогие) методы должна применять другая сторона. Ресурсы цензоров не безлимитные, и поэтому вместо сложных и дорогих эвристик они начинают активно использовать простые и тупые с огромным collateral damage (как например Роскомнадзор устроил резню в попытках заблокировать Телеграм, или как в Иране одно время забанили вообще все браузеры и клиенты с TLS fingerprint'ом похожим на определенную версию Google Chrome - вообще шиза). В итоге из-за действий госцензоров страдают даже люди и компании, вообще далёкие от темы блокировок.


      1. LuigiVampa
        03.12.2023 13:43
        +1

        Помню, пользовался пару лет назад Firefox-ом c eSNI, в сочетании с dns-over-https это позволяло без VPN-ов посещать большинство заблокированных ресурсов (те что сами поддерживали TLS 1.3 и хостились за CDN). А потом в какой-то день Mozilla вдруг объявили что убирают поддержку eSNI из браузера и разом её выпилили, сказав что "это был не стандарт, а драфт, и вообще случайный эксперимент, и на замену ему сейчас придёт полноценный ECH". Но вот только несколько лет уже прошло, ECH так полноценно и не работает, а вот eSNI наоборот - реально работал, ещё несколько лет назад и реально решал проблему цензуры. Выводы, как говорится, делайте сами


        1. MiraclePtr Автор
          03.12.2023 13:43

          ECH так полноценно и не работает, а вот eSNI наоборот - реально работал, ещё несколько лет назад и реально решал проблему цензуры. Выводы, как говорится, делайте сами

          eSNI "решал проблему цензуры" только потому, что им тогда пользовались полтора анонимуса и полторы CDN, и российские цензоры за него ещё не взялись всерьез, этакий Неуловимый Джо. Подключения с ECH (который сегодня уже используется массовее, чем eSNI тогда, в Мозилле он тоже есть) сейчас в ряде стран цензоры просто блокируют без разбора, и точно так же eSNI цензоры могли легко блокировать уже тогда, см. ссылку выше, там как раз про 2020 год. А в России палки в колеса для любителей eSNI цензоры начали успешно вставлять ещё в 2019-м.

          Так какие выводы мы должны сделать?


          1. LuigiVampa
            03.12.2023 13:43

            Справедливо. Тогда был действительно период, когда для цензоров шифрование SNI, закрывающее один из самых удобных способов быстро и дёшево ограничить нужные соединения, было относительно в новинку и не носило массовый характер. Сегодня разумеется этот вопрос стоит более остро, цензоры тоже немного разобрались с тем как там оно технически устроено, помню какой-то сумрачный гений из госдумы даже предлагал полностью запретить и блокировать TLS 1.3.

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


  1. Bega
    03.12.2023 13:43
    +2

    Я как-то настраивал там вебсокет по tls между fastly и сервером, могу ещё раз обкатать и рассказать что надо сделать для


    1. Bega
      03.12.2023 13:43
      +1

      Сразу из коробки hiddify работает с fastly. В settings > domains > mode = cdn. В domain пишете свой домен подключенный к cdn, в поле tls domain fronting добавляете домен для фронтинга.


      1. Bega
        03.12.2023 13:43

        @MiraclePtr глянете пожалуйста лс


        1. MiraclePtr Автор
          03.12.2023 13:43

          До вечера постараюсь ответить


      1. Kameleon3107
        03.12.2023 13:43

        Перспективная панель. Как оцените в сравнении с x-ui/3x-ui, если пробовали их?


  1. karavan_750
    03.12.2023 13:43
    +1

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

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

    Я в похожей ситуации (некоторый сервис ввел ограничения на резидентов РФ) решил "поселиться" за рубежом, не покидая страны пребывания — РФ. Первое предложение сервиса подтвердить мое перемещение путем демонстрации платежки за коммунальные услуги я отверг по причине "арендного" жилья. Тогда они предложили через банковскую выписку.

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


    1. al01555
      03.12.2023 13:43

      Не понял. Банк ваш, в котором адрес поменяли - иностранный? Или русский?


      1. karavan_750
        03.12.2023 13:43

        Банк российский. Подтверждений нового места жительства не требовали.


  1. venanen
    03.12.2023 13:43

    Отличная статья, как всегда. И пользуясь случаем - ни у кого нет часом архива публикаций уважаемого автора( @MiraclePtr)? Чтобы спокойно архив в облако закинуть на будущее?


    1. karavan_750
      03.12.2023 13:43
      +3

      ни у кого нет часом архива публикаций уважаемого автора( @MiraclePtr)?

      Веб-архив трудится над каждой новой статьей )


  1. Spyman
    03.12.2023 13:43

    Уважаемые эксперты - а нет ли чего нибудь супер простого типо algo или готового решения в docker контейнере с хорошим уровнем недетектируемости? Чтобы в 2 команды развернул, поставил клиент и поехало?

    Я так полтора года назад развернул wg через algo, это заняло около часа и прекрасно работает, но чувствую wg должно не проживёт(
    Но все статьи которые сейчас вижу требуют что-то типо пол дня - день просидеть за настройкой.

    Может есть какой нибудь контейнер где уже всё готово, который переживёт блокировки на уровне протоколов хотя бы.