РКН против приложения «Навальный»: борьба за доступность
2021 год в России запомнится беспрецедентной волной судебных и внесудебных блокировок ресурсов средствами DPI. 26 июля Роскомнадзор заблокировал множество наших ресурсов: блог Навального navalny.com, сайт сети региональных штабов shtab.navalny.com, сайт Фонда борьбы с коррупцией fbk.info и другие. Под блокировки попали даже сайты проектов «РосЯма» и «РосЖКХ». Все перечисленные ресурсы были заблокированы на основании требования Генеральной прокуратуры РФ как содержащие призывы к массовым беспорядкам, осуществлению экстремистской деятельности, участию в массовых (публичных) мероприятиях, проводимых с нарушением установленного порядка, и информационные материалы организаций, деятельность которых признана нежелательной. Сайт проекта «Умное голосование» заблокировали за неделю до выборов — 6 сентября. С конца августа РКН развернул настоящую войну с приложением «Навальный» и чуть не сломал весь российский интернет.
В этом посте мы расскажем о противостоянии, которое развернулось между нашей командой и РКН летом — осенью 2021 года: о технологиях по обходу блокировок, о собственной системе мониторинга, о том, как нам удалось «обучить» РКН регулярным выражениям. Расскажем, как РКН был вынужден пойти на крайние меры, попытавшись заблокировать публичные DNS в России, и каких результатов нам удалось достичь.
Введение
Наша команда рассматривала сценарий блокировок заранее. Еще в 2020 году было решено использовать мобильное приложение как основной инструмент доставки до пользователей постов в блоге и рекомендаций «Умного голосования».
С момента введения повсеместного DPI в России за доступность сайтов стало бороться все сложнее. Дело в том, что протокол TLS не предусматривает шифрование изначального «рукопожатия» между клиентом и сервером. Когда во всем мире обнаружился дефицит IPv4-адресов, виртуальный хостинг (когда несколько разных доменов работают на одном IPv4-адресе) пришлось широко использовать и в TLS. Клиент во время рукопожатия передает доменное имя сайта (SNI — Server Name Indication), а сервер в ответ отправляет сертификат для этого домена. Этим и пользуются разработчики DPI, позволяя различать трафик, идущий на один и тот же адрес, по SNI и блокируя только тот, что им нужно. Во время разработки стандарта ESNI (Encrypted SNI, позволяющего шифровать заголовок SNI) обнаружились неустранимые проблемы, и на замену ESNI пришел протокол ECH (Encrypted Client Hello), в котором шифруется все рукопожатие со стороны клиента.
Стандарт ECH еще не стал всеобщим. В IETF он находится в фазе активной разработки в статусе draft. Последнее обновление документа с описанием стандарта было как раз в августе 2021 года. Следовательно, поддержки этого протокола на конечных клиентах (браузерах) не предусматривалось. Мы понимали, что успешно скрыть домен в HTTPS-трафике от РКН нам не удастся. Поддержка доступности web-сайта стала весьма проблематичной задачей.
Когда требование Генпрокуратуры о блокировке было исполнено, сетевое сообщество начало организовывать прокси до заблокированных ресурсов команды Навального, однако на практике это оказалось неэффективным. Любой адрес, замеченный РКН, рано или поздно попадал под внесудебную блокировку и моментально становился недоступным. Было понятно, что любые публично распространенные прокси, вне зависимости от доменного имени, будут успешно заблокированы.
После вступления блокировок в силу мы первым делом провели простой эксперимент: переключили домены наших ресурсов на IP-адреса AppEngine. Были возможны три варианта: либо блокировка полностью отключилась бы (если айпишники AppEngine находились в белом списке у РКН), либо весь AppEngine в российском сегменте интернета оказался бы заблокированным, либо осталась бы только блокировка по DPI. Результаты теста подтвердили наши ожидания — доступность не возросла. Надо отметить, что РКН хорошо подготовился и начиная еще с 2016 года явно обеспечил покрытие DPI на большинстве провайдеров России, в том числе DPI «по сигнатурам» (он же ТСПУ).
Система мониторинга
Здесь стоит рассказать о средствах мониторинга, с помощью которых мы проверяли доступность наши ресурсов.
Блокировки через «технические средства противодействия угрозам» (ТСПУ) нельзя отследить традиционными методами, с помощью реестра РКН или так называемых «Дельт». Нет никакого подлинного списка ресурсов, которые блокировались на уровне ТСПУ. Блокировки приобрели не подотчетный и непрозрачный характер. Поэтому, чтобы отслеживать работоспособность ресурсов, пришлось разработать систему отслеживания на уровне провайдеров РФ.
Для реализации такой системы мы приобрели комплекты Raspberry Pi 3B. Наши читатели наверняка знают, что мы фанаты «Малинок», и в этот раз выбор снова пал на них. Эти микрокомпьютеры обладают полноценной Linux-системой на борту, а также оборудованы сетевой картой с портом RJ45, дешевы и просты в обслуживании.
Модель RPi
Мы подготовили комплекты Pi для волонтеров, которые согласились установить у себя эти импровизированные «зонды». В каждом из них была скомпилирована ОС на базе Ubuntu 20.04 — так, чтобы волонтеру было достаточно просто подключить Raspberry Pi в сеть. Малинки совершали попытки обращения к нужным ресурсам и отслеживали статус, отсылая его нам.
Для безопасности мы скрыли весь служебный трафик Pi в VPN-сеть. Оставили только GET-запросы и скачивание пакетов при обновлении.
Мы постарались охватить своей сетью провайдеров по всей стране. В первую очередь, конечно, нас интересовали провайдеры с ТСПУ, но в связи с тем, что нет никаких официальных публичных списков провайдеров с этим «черным ящиком» на борту, мы пытались придерживаться самых крупных — большой тройки, Ростелекома, Дом.ру и подобных. Сеть составляли где-то 50% провайдеров с ТСПУ и 50% без.
Пример download показателей обращения к ресурсу системы мониторинга
Для отправки запросов, хранения полученных данных и алертов мы воспользовались Zabbix. Чтобы отслеживать блокировки сайтов, использовалась встроенная функция «веб-агента» и кастомные скрипты, исполняемые на зондах.
Дашборд со сканерами системы мониторинга доступности
Для обработки и вывода данных использовалась Grafana.
Дашборд с гистограммой системы мониторинга доступности | Grafana
В дополнение был написан API-микросервис, которому мы дали имя «Navalny Hello». Его основной задачей было выдавать по любому домену информацию о блокировке. Сервис работал на основе Pi-сканеров и выдавал скоринг для каждого запрашиваемого адреса.
Пример ответа сервиса «Navalny Hello» по запросу доступности ya.ru
Требования к приложению
В приложении «Навальный» важнее всего было обеспечить доступность блога и проекта «Умное голосование». Мы публикуем свои рекомендации по голосованию за три дня до выборов, чтобы власти не могли снять кандидатов, за которых мы советуем отдать голос. При этом основная функция приложения — поиск кандидата по адресу (пользователь вбивает свой адрес и получает конкретную рекомендацию). Таким образом, залить список кандидатов прямо в приложение через стандартное обновление было проблематично, — тем более что обновление в Google Play и Apple Store могут рассматривать от нескольких суток до нескольких недель, и такого запаса времени у нас просто не было.
Учитывая необходимость постоянной синхронизации приложения с адресами нашего бэкенда, мы выделили в основных требованиях несколько пунктов:
защита от блокировки IP-адресов;
защита от блокировки доменных имен;
обход DPI-средств провайдеров.
Был подготовлен специальный протокол, который поддерживал технологии DoH-резолвинга и SNI-фейкинга. С помощью закодированного дискавери, представляющего собой JSON-структуру с электронной подписью для защиты от replay-атак, мы смогли «научить» приложение обнаруживать через публичные DNS актуальные адреса бэкенда для обновления контента. Когда РКН банил наш адрес, мы создавали новый, обновляли дискавери, контролировали значение TTL записи, чтобы избежать ненужного кэширования, и таким образом перед очередным запросом пользователя сообщали для него новый маршрут обращения. К моменту блокировки сайтов приложение работало в Google Play и Apple Store с данной версией протокола.
Ротация «на опережение»
В «мирное время» секретные механизмы предусмотрительно не были включены. Специалисты РКН не совершали никаких дополнительных действий после блокировок сайтов и только 20 августа перешли в наступление и предприняли первые попытки заблокировать адреса приложения. Чтобы не раскрывать все наши возможности до дня выборов, мы решили поиграть в «догонялки» с РКН — обновляя дискавери и доставляя пользователю необходимые адреса.
По первым наблюдениям, РКН осуществлял мониторинг чуть ли не вручную. Мы запустили скрипт, который генерил доменные адреса третьего уровня, например 1np13q836n.rkngov.com, готовил для них необходимый бекенд и отдавал в дискавери. Согласно нашему мониторингу, каждый новый адрес третьего уровня попадал в реестр и разливался в качестве правила по провайдерам в течение 13 минут. Когда в РКН удостоверились, что мы осуществляем ротацию доменов исключительно третьего уровня, они наконец решились блокировать всю вторую зону целиком.
Мы вернулись к варианту хостинга на AppEngine. Каждый проект в AppEngine автоматически получает служебное доменное имя, соответствующее идентификатору проекта. Скажем, проект navalnyapp был доступен на домене navalnyapp.appspot.com. Однако в документации на AppEngine мы обнаружили, что сайты получают и другие служебные домены, например <версия>-dot-<проект>.appspot.com. Если в качестве версии указать любую строку, для которой даже нет версии приложения, то осуществляется fallback на основную версию. В итоге адрес для ротации в дискавери был заменен на *-dot-navalnyapp.appspot.com. Основная задумка заключалась в том, что в данном случае нам не обязательно было «заранее готовить» новый адрес. Достаточно было дописать перед «dot» любое слово, и такие адреса моментально мапились на наш проект. РКН стал получать на своих сканерах «адреса-приветы» от нашей команды — putinprivet-dot-navalnyapp.appspot.com
, putinvor-dot-navalnyapp.appspot.com
, 123putinuhodi-dot-navalnyapp.appspot.com
, 321putin…
и т.д.
Вы можете проверить это сами: придумайте любой аналогичный адрес, вбейте его в браузер — и обнаружите на корневом адресе блог Навального. Впрочем, сейчас все эти адреса заблокированы.
Подобным образом мы могли осуществлять ротацию в любом объеме и в любое время. На сканерах своего мониторинга мы мгновенно увидели 100% доступность, и РКН встал перед выбором: либо обучить свой блокирующий софт регуляркам, либо заблокировать всю зону appspot.com целиком.
Дашборд с показателями доступности приложения при ротации служебных доменов -dot-navalnyapp.appspot.com
Интересно заметить, что на любой «нестандартный» ход РКН реагировал с предсказуемой задержкой. Если мы что-то меняли в будни, условно говоря, с 9 до 17, то реакция следовала в течение часа. А если дожидались вечера (лучше, конечно, вечера пятницы), то 100% доступность сохранялась до 9 утра следующего рабочего дня. Видимо, у РКН была дежурная смена юных падаванов, которые делали какие-то совсем простые вещи, и настоящие специалисты, доступные только в рабочее время.
Пока РКН «учился в регулярки», мы смогли выиграть время и апгрейднуть скрипт ротации наших адресов. В связи с тем, что любые из них блокировались сразу по второй зоне целиком, мы написали обновление. Скрипт заблаговременно и массово регистрировал домены второго уровня у одного из хостеров. Затем регистрировал их в CloudFlare, добавлял в качестве кастомного домена к нашему проекту в AppEngine (это было сделано для того, чтобы исключить блокировки на тех провайдерах, которые не умели в DPI), ждал выпуска сертификата гуглом и каждые n минут подсовывал эти домены приложению, предварительно проверяя через наш вышеупомянутый сервис «Navalny Hello», не заблокированы ли они. Таким образом мы могли переиспользовать адрес, если РКН со временем внезапно решил бы его «разблокировать». Благодаря непрерывному мониторингу, ускоряя или замедляя скрипт, мы могли определить, за какое время РКН замечал новые адреса второго уровня. В очередной раз на сканеры нашего противника посыпались «адреса-приветы» самых дешевых доменных зон, например: www.roskomnadzoruhodi.website
, www.svobodypoltzakluchennym.xyz
, www.rknidiotdohni.fun
, www.privetput1nu.online
, www.rknprivet.club
и т.д.
Вы можете проверить — эти адреса и сейчас заблокированы у провайдеров с ТСПУ.
CDN вступают в борьбу
Мы в очередной раз выиграли время. Но предварительная покупка доменов, пускай даже в самых дешевых доменных зонах, в долгосрочной перспективе и в больших объемах требует затрат, а от идентификации адреса до распространения блокировки на провайдерах, согласно нашим сканерам, стало проходить не больше минуты. Так что мы решили обратиться за адресами к известным CDN-провайдерам, таким как Bunny, Fastly, Amazon.
Идея заключалась в том, что РКН не решится целиком блокировать доменную зону второго уровня, предоставляемую публично известными CDN-провайдерами, и мы сможем относительно дешево проксировать трафик на бэкенд с их помощью через дискавери приложения. Пошаманив с настройками кэширования, мы запустили скрипт ротации доменов с CDN от Bunny.
К моменту, когда мы израсходовали более 6000 подобных адресов, РКН также провел несколько тестов и все-таки решился на полную блокировку b-cdn.net на ТСПУ. Практически сразу мы получили письмо от основателя Bunny о том, что они вынуждены приостановить действие нашей учетной записи, поскольку это негативно сказывается на доступности их сети. Вероятнее всего, блокировкой РКН был задеты крупные пользователи Bunny в России.
Письмо от основателя Bunny c объяснением причин блокировки аккаунта
В качестве резервного варианта мы переключили ротацию на Fastly CDN. Это работало нормально, и на этот раз РКН уже не решался блокировать весь второй уровень более известного CDN. Но из-за ограничений по количеству создаваемых зон на аккаунт (мы не всегда могли освобождать старые зоны, и из-за багов в приложении в некоторых случаях приходилось их «копить», чтобы устройства, получившие старую запись дискавери, могли их использовать неограниченно долго) в конечном счете мы перешли на адреса Amazon. Довольно легко получилось арендовать на старте квоту со значением около 10 тысяч адресов в доменной зоне cloudfront.net.
На этот раз мы наконец создали очевидную проблему для РКН. Адреса пачками и довольно быстро готовились по ранее опробованному скрипту. Наши сканеры зафиксировали рост доступности.
Доступность адресов CloudFront при использовании в ротации приложения «Навальный»
DNS под угрозой. Domain Fronting, DOH-резолвинг и NewNode
РКН оставалось разве что блокировать Amazon целиком. И в этом случае у нашего приложения в запасе еще оставался секретный механизм SNI-фейкинга. Именно в этот момент в РКН впервые задумались о запрете на использование публичных систем доменных имен и начали готовить российских провайдеров к отключению Google и CloudFlare DNS, рассылая соответствующие письма с требованиями.
В РКН даже провели тесты кратковременной блокировки DNS, что и зафиксировал наш мониторинг и пользователи российского сегмента интернета:
Мы были готовы и к такому развитию событий. Все это время параллельно работали над дополнительными обновлениями по обходу блокировок для нашего приложения. Мы полагали, что на один день забанить Tor ради большой цели для РКН, в принципе, не будет проблемой. Конечно, у этого был бы медийный эффект, но, вероятнее всего, кроме гиков, этого бы почти никто не заметил. Так что идею использовать Tor мы отложили. Была подготовлена имплементация технологии Domain Fronting в качестве дополнительного инструментария, которым мы могли аналогичным образом управлять на стороне клиента через дискавери. А также DOH-резолвинга на случай полной блокировки DNS в России и решения проблемы обновления самого дискавери.
Идея была проста. Вышеупомянутый navalnyapp.appspot.com, (а вообще говоря, любой *.appspot.com) можно фронтить в любой ${garbage}.appspot.com. Мы также нашли возможность фронтинга еще через пару популярных ресурсов, которые РКН вряд ли решился бы полностью отключить в России (мы намеренно не хотели бы раскрывать их в этом посте). Добавили этот функционал в приложение. А в качестве DoH-резолвинга расширили параметры нашего дискавери до получения записей с нескольких storage-провайдеров, таких как Google Cloud Storage и Amazon S3, на случай блокировки Google и Cloudflare DNS.
Помимо всего прочего, в приложении закладывались и альтернативные, весьма экспериментальные способы обхода блокировок, включая использование механизмов P2P-обмена данными. В конце августа нам удалось сделать экспериментальную сборку приложения с внедренным SDK под названием NewNode. NewNode, а также экспериментальный мессенджер FireSide — продолжение исследовательских работ, которую ведет команда, известная другим инновационным мессенджером FireChat. Они же разработчики известного протокола BitTorrent. По задумке, эта штука должна обеспечивать связность даже при полном отключении интернета — просто передавая данные от клиента к клиенту через встроенные в мобильные телефоны модули беспроводной связи Bluetooth и Wi-Fi. SDK NewNode специально создан, чтоб научить мобильные приложения использовать для передачи данных встроенные механизмы BitTorrent, LEDBAT и передачу данных от устройства к устройству (Device-to-Device Communications — D2D). Эта тема, пожалуй, заслуживает отдельной статьи, но если коротко объяснять принцип работы, то для разработчика SDK выглядит как прокси, который использует собственный транспорт для передачи данных: сильно переделанный DHT в качестве транспорта, D2D для организации каналов в случае недоступности интернет-ресурса и LEDBAT, который оркеструет все доступные способы коммуникации, выбирая самый эффективный в данный момент времени.
В постановлении РКН о блокировке публичных DNS для провайдеров предполагалась также блокировка DNS-over-UDP. Именно этот сервис использует библиотека NewNode, что только укрепляет нас в мысли о направленности данных действий исключительно против нашего приложения. Примерно в то же время была замечена и блокировка приложения NewPipe в части YouTube-клиента по TLS-отпечаткам. РКН, по всей видимости, проводил предварительные тесты (или перепутал NewNode или NewPipe? :))
Последняя сборка приложения «Навальный» содержит NewNode и потенциально будет работать (в крупных городах с большой плотностью населения) даже при полном отключении интернета.
Заключение
Паралельно с ежеминутными блокировками, РКН продолжал отправлять запросы в Apple и Google с требованиями удалить приложение «Навальный». Письмами дело не ограничилось — представителей Apple и Google вызвали в Совет Федерации на заседание комиссии по защите суверенитета: неисполнение требований РКН было воспринято как иностранное вмешательство в выборы. В московский офис Google незадолго до выборов приходили силовики. Дошло и до прямого шантажа — по данным издания Bloomberg, российским сотрудникам Google угрожали тюрьмой, если компания не исполнит требования властей.
Письмо от РКН с запросом удаления приложения «Навальный» в App Store service
Само собой, все эти процессы усложняли ревью любых наших обновлений. Рассмотрение зависало на несколько дней. Последние обновления, c domain-fronting и DoH-резолвингом, мы отправили 10 сентября. Очевидно, РКН рассматривал два сценария: либо приложение удастся удалить, либо придется ломать половину российского интернета, отключив публичные DNS. К счастью для РКН, им удалось добиться первого сценария. В конце концов, после почти недельного ожидания, наши обновления были подтверждены магазинами приложений, но одновременно с этим их моментально удалили из магазинов. Это случилось утром 17 сентября, в первый день выборов. А в ночь на 18 сентября Павел Дуров, сославшись на действия Apple и Google, заблокировал телеграм-бота «Умного голосования».
Наша команда распространяла списки с рекомендациями кандидатов через репозиторий в Github, Google Docs, YouTube и APK-сборку Android c последними алгоритмами обхода блокировок. Аккурат перед днем голосования мы успели закинуть в магазины приложений и последнее обновление с обычным PDF-файлом, где содержался список рекомендованных кандидатов. Так что те немногие пользователи, которые все-таки успели обновить или загрузить сборку, могли потрясти телефон и посмотреть в PDF список кандидатов даже без активного подключения к интернету.
В РКН понимают, что, как только будет принят стандарт ECH и его реализация доедет до серверов крупных сервисов и в популярные браузеры, бороться с непокорными сайтами станет намного сложнее. DPI придется полагаться исключительно на фингерпринтинг со всеми вытекающими ложноположительными и ложноотрицательными проблемами. Иными словами, им придется или поломать весь интернет, или сдаться. Поэтому на следующий день после выборов Министерство цифрового развития, связи и массовых коммуникаций РФ разместило для общественного обсуждения проект федерального закона, устанавливающего запрет на использование на территории РФ протоколов шифрования, которые позволяют скрыть имя (идентификатор) интернет-страницы или сайта. Нет никаких сомнений, что это происходит для «легализации» борьбы с новыми методами обхода блокировок, подобными тем, над которыми работала наша команда в этом году.
Такие законы с каждым днем делают российский сегмент интернета все хуже — менее безопасным и менее приватным. Наша задача — отстоять его.