Вопросы безопасности Telegram

Telegram, MTProto 2.0, и все-все-все

Привет!

Это будет достаточно необычная статья, потому что стандартно я на странице с полезными статьями публикую учебные материалы. Здесь же – что-то вроде “нас часто спрашивают” вкупе с “чтобы сэкономить время на постоянных объяснениях”.

Мессенджер Телеграм недавно попал под блокировку со стороны Роскомнадзора – по причине того, что руководство отказалось сотрудничать с правоохранительными органами, которые по решению суда запросили какую-либо информацию о 6 абонентах. Следствие запросило любую информацию – даты и IP-адреса входов, списки контактов и прочее – но руководство Телеграма решило исполнить мы свободные и против Системы, а ряд СМИ и вовсе переврал ситуацию, рассказывая о

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

Что же по факту с вопросами безопасности Телеграм?

Технологичность

При блокировке Телеграм первым делом началось муссирование тезиса о безусловной, полной и окончательной хайтековости этого сервиса. Аудиторию буквально унавоживали ковровыми бомбардировками про “Это уникальный, прорывной, не имеющий аналогов, безупречный, супер-сервис” – ну а потом, по готовой почве, уже работали очевидным выводом “… а значит запрет его – это анти-технологичность, скатывание вниз в кромешный ад и ужас, средневековье и прочее”.

Если честно, то на рынке сейчас пара десятков крупных мессенджеров и сотни прочих, поменьше. Взяв тот же Skype мы увидим тьму возможностей – от совместного использования десктопа, видеоконференций, затейливых схем соединения голосовых звонков и конференц-связи с обычной телефонной сетью до интеграции с LiveID, PowerPoint, использования HoloLens и прочим. Взяв ту же древнюю ICQ – ну или какой-нибудь Pidgin – можно вообще поразиться объёму функциональности и списку доступных плагинов для таких систем.

Почему же так упорно вбивается тезис “Телеграм – это абсолютно прорывное и технологичное, пользование им – это признак принадлежности к будущему и хайтеху”? Безусловно, данный метод – объявление какого-либо продукта или сервиса “признаком принадлежности к касте особых людей” – давнишний и всегда рабочий. Но в данном случае, думаю, всё ещё проще.

Дело в том, что в настоящее время наблюдается культ комфорта и некий комфортоцентризм любого UX. Абсолютно всё, что проще, объявляется святым и прорывным. Если какое-то действие делалось в 5 кликов мышки, а в новой версии ПО делается в 4 – то это прорыв и хайтех, без вариантов и обсуждений. Интерфейс в стиле “детская книжка с крупными буквами и разноцветными картинками, 3-5 строчек текста на странице” – идеал.

В случае с Телеграм мы видим как раз крайне урезанный по функционалу, для середины 2018 года, программный продукт – но простой. Крайне простой, шустро работающий и имеющий минимум настроек.

Поэтому технологичностью объявляется именно это. Хотя полностью было бы корректнее – Телеграм – это технологичный [с точки зрения простоты интерфейса и упрощённый по функционалу] продукт.

Ну а теперь к безопасности.

Безопасность Телеграм

Вопросы безопасности базируются на изучении открытой документации и открытых исходниках некоторых клиентских приложений. Основной акцент, как понятно – на протоколе MTProto 2.0 и e2e-шифровании в “секретных чатах”.

Сразу хочется заметить, что исходники на гитхабе обновляются не параллельно с выходом новых версий Telegram – что, в общем, вызывает очевидные вопросы, но не суть.

Вопрос по алгоритму Диффи-Хеллмана-Меркля

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

Алгоритм Диффи-Хеллмана-Меркля уязвим для атаки MitM, “человек посередине” изначально, и был уязвим для неё всегда. Дабы не переписывать документацию на 100500 раз задокументированный протокол, оставлю здесь ссылку на русский вариант его подробного описания и буду в дальнейших рассуждениях предполагать, что вы по ней сходили.

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

Но если сервер может модифицировать данные во время согласования ключей “на лету”, то всё наоборот – алгоритм DH ничего не может сделать.

В самом деле, промежуточный участник может согласовать с каждым из двоих свой ключ, имитируя “вы напрямую друг с другом общаетесь”. Единственная защита от этого – сверка ключевого материала после установки сессии и до начала отправки по ней секретных данных. Данная возможность в Telegram есть – но учитывая, что пересогласование ключей идёт достаточно часто – раз в 100 сообщений – многие ли действительно вручную сверяют этот параметр? По сути нужен механизм, который бы после каждого rekey позволял бы как-то по другому каналу удостовериться, что у каждого из 2 участников ключ сменился на одинаковый. Пока его нет – сервер в любой момент может сделать вышеупомянутое действие, никакой гарантии или возможности сделать проверку на невозможность такого действия – нет.

Утверждение о “раз там DH, то в принципе никак сервер не может получить доступ к данным” – ложное. Оно нуждается в дополнении “если проводится постоянный дополнительный контроль на фазе работы протокола и по завершению работы оного”. Сам алгоритм не просто уязвим, а полностью беззащитен перед MitM. Он спасает от eavesdropping, это – другое.

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

Вопрос по сетевым параметрам сессии

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

Почему так – вопрос. Ведь такая возможность сразу же и полностью убрала бы все вопросы “может ли сервер иметь доступ к данным”.

Вопрос по криптографическим параметрам сессии

Процитируем документацию:

User A executes messages.getDhConfig to obtain the Diffie-Hellman parameters: a prime p, and a high order element g.
Executing this method before each new key generation procedure is of vital importance. It makes sense to cache the values of the parameters together with the version in order to avoid having to receive all of the values every time. If the version stored on the client is still up-to-date, the server will return the constructor messages.dhConfigNotModified.
Client is expected to check whether p is a safe 2048-bit prime (meaning that both p and (p-1)/2 are prime, and that 2^2047 < p < 2^2048)

Клиент не генерит простое число для DH. Он запрашивает его у сервера и лишь поверхностно проверяет. Вопрос генерации “хороших простых чисел” и проверки их на “хорошесть” я разобрал в статье про SSH, скажем простое – при утверждаемом в документации “меняем ключ на каждые 100 сообщений” секретные чатики должны были бы ощутимо подлагивать, потому что пересогласование приводит к получению нового числа и перепроверке его на простоту. Судя по тому, что это не происходит, имеет место какая-то ускоренная/упрощённая проверка присланного сервером числа. Почему так?

По сути, все современные используемые тесты на простоту являются вероятностными. Провести полноценный тест – т.е. честно тестово поделить число масштаба 2^2048 на все простые числа до него – вычислительно невозможно. И по причине сложности деления, и по причине нахождения всех простых чисел меньше указанного. Чтобы проще представлялись масштабы, 2^2048 – это десятичное число с чуть более чем 600 знаками. Составление же даже таблицы “все простые числа до 2^100” и сохранение её локально – уже проблема как вычислительная, так и хранения.

Раз с полноценными тестами у нас ничего не выйдет даже если клиентская система будет заранее к ним готовиться (она, говоря проще, будет тогда только готовиться к ним, и больше ничего, на эту задачу можно отправить сколько угодно вычислительной мощности), то в дело вступают вероятностные тесты. Два самых популярных – это Соловея-Штрассена и Миллера-Рабина. Оба этих теста умеют говорить “Данное число точно составное”, либо “Данное число предположительно простое”. Именно в таких формулировках, т.е. не-прошедшее тест число – точно на что-то делится кроме себя и единицы. А вот прошедшее – вроде как не делится.

Всё просто – клиенту действительно, зная “глубину” и алгоритм проверки, можно подсунуть число, которое он будет считать простым и не просто считать, доверяя серверу – а даже если и проверит, то со своими методами убедится, что оно не составное.

Так что “нам сервер присылает число, а мы его проверяем” нуждается в корректировке – учитывая априори разные мощности клиентского устройства и сервера, а также характеристики алгоритмов генерации и проверки, можно утверждать, что у сервера Телеграм есть реализуемая на практике и не отслеживаемая локально (логов нет, старых чисел нет) возможность прислать “слабое” число, в результате чего компрометация сессии – дело очень простое.

Но верующие в “безопасность Телеграм” не заморачиваются такими деталями – джентльменам ведь верят на слово, так?

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

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

Дело в том, что когда prime у DH прошито на клиентской части, то его можно разово на аудите продукта проверить на “насколько оно простое” и, в случае провала тщательной проверки, забраковать всю систему. На клиентской системе вы не можете “на лету” генерить стойкие prime для “старших” групп DH – для этого у вас банально не хватит вычислительных мощностей. Настолько, что даже “установить 1 сессию раз в секунду” будет проблемой. Вы можете пройти по этой ссылке и попробовать создать prime для DH и проверить их на качество, оценив и затраченное время, и процент prime, которые оказались не prime.

Поэтому число вам присылает добрый сервер, а вы его “по быстрому” проверяете. Добрый сервер никто не удерживает от того, чтобы для специальных сессий – по желанию сервера – присылать особые, проходящие клиентский тест на простоту числа, не являющиеся простыми. Такие существуют в природе.

В пользовательском интерфейсе Телеграм отсутствует возможность увидеть текущее p, использованное при последнем прогоне протокола DH. Также отсутствуют какие-либо исследования, в которых присылаемые сервером числа журналировались и впоследствии проверялись на простоту чем-то более мощным, чем тестом, встроеным в клиентское ПО. Ничего не мешает серверу Телеграм прислать вам лично такие параметры DH, которые сделают криптоанализ сессии тривиальным. Вы этого просто не увидите. Старые параметры не хранятся на клиенте, но могут храниться на сервере.

К вопросу о том, насколько вопрос “какой prime используем на DH-обмене” является серьёзным, можно глянуть RFC 5114. Т.е. выверенные “реально и действительно простые числа” опубликованы и надлежат к использованию в ряде специфичных проектов. Авторство, кстати – NIST, после утверждения со стороны NSA.

Время шуток про тащмаёра и сертифицированную свободу, не так ли?

Вопрос по исходным кодам

Исходники клиентской части Телеграма доступны, но тут вступает в силу основная проблема СПО.

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

Вопрос “насколько то, что выложено на гитхабе, действительно является текущей версией Телеграм” – актуален. Вдобавок актуален вопрос “нет ли в коде буквально крохотных различий, благодаря которым сервера Телеграм могут различить “свой стандартный” клиент и “то, что собрано из исходников”. Если так, то можно иметь идентичный протокол MTProto 2.0, но при использовании “самосборного” клиента применять другую логику поведения со стороны сервера. Мы никак не можем это узнать, т.к. сервер – “чёрный ящик”. Надо проводить полновесное исследование, сравнивая фактический машинный код и поведение у “обычного” телеграм-клиента и у собранного из исходников с гитхаба.

Вопрос по энтропии

Откроем документацию.

If the client has an inadequate random number generator, it makes sense to pass the random_length parameter (random_length> 0) so the server generates its own random sequence random of the appropriate length. Important: using the server’s random sequence in its raw form may be unsafe. It must be combined with a client sequence, for example, by generating a client random number of the same length (**client_random**) and using final_random := random XOR client_random.
Client A computes a 2048-bit number a (using sufficient entropy or the server’s random; see above) and executes messages.requestEncryption after passing in g_a := pow(g, a) mod dh_prime.

Говоря проще, у клиентского ПО есть некий критерий “мой генератор энтропии плоховат, возьму с сервера”.

Про генерацию случайных чисел я уже писал отдельную статью, поэтому предположу, что вы её уже прочитали.

В документации телеграма, а также в документации на клиентское ПО нигде не указано, как именно клиент принимает такое решение. Вопрос исчерпания пула энтропии – вполне реальный, тут никто не спорит; другое дело, что противомерой является не, допустим, создание своего пула с RKG или чем-то подобным, а-ля kernel 4.8 с /urandom и бесконечной выдачей на основе ChaCha20, а “пусть тогда сервер выдаст”. Это удивительный ход для продукта, подчёркивающего безопасность и децентрализованность.

Помимо того, что такая схема сама по себе примечательна, сразу же возникает возможность простого действия – зная, как именно клиент принимает решение “что-то мой генератор энтропии слабоват – попрошу случайные числа у сервера”, можно вынудить его это сделать. Возможно, многократным запросом rekey, или чем-то подобным – то есть сервер, зная всю техническую реализацию пула энтропии у клиента, зная как определяются критерии исчерпания оного, просто запрашивает пересогласование ключей сессии несколько раз – ведь ничего этого не журналируется, клиент это просто не видит. Главное, что есть сама возможность и предсказуемый алгоритм поведения.

В документации указывается, что полученная с сервера энтропия должна XOR’иться с клиентской – так, мол, идёт “только усиление”, ведь 2 энтропии в XOR – это ещё более энтропия.

Да, 2 энтропии в XOR – это хорошо. Но две энтропии. А в данном случае одна из них – предсказуемый генератор – у нас клиент же запрашивает у сервера энтропию в ситуации “мой родной источник стал гнать одни единички” и подобной, так? – плюс полученное с сервера – уже плохо.

Пример – если у вас генератор выдаёт случайные числа, регулярно по некоему критерию проводит оценку “насколько они случайные”, и в случае, если он выдаст число 58, алгоритм понимает “Вышло не случайное” и запрашивает энтропию у сервера, и потом её XOR’ит с имеющейся (т.е. известным числом 58), то никакого улучшения безопасности от этой дополнительной операции XOR мы не увидим. По сути, мы имеем дело с имитацией усиления энтропии, взятой с сервера – ведь она XOR’ится только с предсказуемой.

Ну а как только клиент перейдёт на запрос энтропии с сервера – дальнейшее обсуждать смысла нет. Вполне очевидно, что скормив клиенту строчку “случайных” байт и сохранив её у себя, сервер идентично воспроизведёт все последующие действия и по установке сессии, и по генерации ключевого материала. Стартовав с синхронизированным генератором ПСЧ-то, да.

Вопрос по обновлениям

Клиентская часть Телеграм достаточно часто обновляется. У подавляющего большинства современных пользователей есть рефлекс, состоящий в “любое обновление – это всё станет лучше, быстрее, безопаснее, добавят функционала и исправят ошибки”, поэтому обновления применяются или автоматически, или вручную по критерию “увидел что есть – сразу поставил”. Если посмотреть размер обновлений, то они достаточно крупные – в десятках мегабайт. Т.е. никто не парится особо с дельтами, diff и прочим – обновляют модули целиком.

Безусловно, обновления делают всё, что перечислено выше – и закрывают обнаруженные уязвимости, и исправляют ошибки, и добавляют функционал. Вопрос только в том, что никто не проверяет, что по факту приходит с обновлениями. Ведь куда как проще сослаться на “там исходники выложены”, правда? А всякие мелкие детали – насколько скачанное обновление совпадает с выложенными в открытый доступ исходниками той же версии – они заминаются. Ведь это надо изучать, проверять. Кто это будет делать? Я не нашёл людей, которые на постоянной основе изучают код клиента Телеграм и хотя бы пытаются сопоставлять декларируемое в плане функционала/изменений с фактическим.

Но попытка обсудить этот вопрос натыкается на глухое урчание со стороны пользователей Телеграм. Притом тех, кто замечательно обсуждает, допустим, закрытый программный код других продуктов. Здесь фактически мы видим психологический момент – некую “подсадку” на ощущение приобщённости к “переднему краю хайтеха”. Эта подсадка достаточно масштабна, её эхо видно и в обычном “а, у тебя телефон не последней модели, ну значит не тянешь, а я-то вот с хайтехом в обнимку”, и в удобном самообмане вида “скачал новую версию софта X – всё реально залетало прямо”. Благодаря этому вырабатывается инстинкт “всё обновить на самые распоследние версии, ведь это по сути приближает меня к некоему хайтеху и будущему”, который после – как и любое предсказуемое поведение пользователей – удобно монетизировать.

В результате разработчик ПО может установить такой темп обновлений, что аудит текущей актуальной версии будет не иметь смысла – всегда будет более новая, и любые вопросы “а почему в версии 8.7.1 по факту, если посмотреть отладчиком, работает так?” упрутся в “да у всех уже 8.7.3, поэтому нет смысла обсуждать старьё 8.7.1” и “а есть версия новее – в ней стопудово всё уже исправили”. Вкупе с выложенными исходниками (какой версии? насколько соответствующими распространяемому через сервис обновлений комплекту исполняемых модулей?) ситуация превращается в патовую – разработчик ПО может делать всё что угодно, добавлять в клиентскую часть что хочется, а также убирать оттуда ранее добавленное. Сочетание:

  • Выложенных исходников некоей версии продукта;
  • Масштабности исходного кода;
  • Темпа обновлений;

делает ситуацию зафиксированной. Пассивность типового потребителя такого сервиса довершает картинку – по сути, люди живут в тезисе “Всё, что делает владелец сервиса – для моего личного блага. За это я в него верую, ведь он меня за руку в светлое хайтех-будущее ведёт. А значит ему всё прощается и он во всём прав. Он всегда всё правильно делает, ведь он мне бесплатно даёт программный продукт, который в моём круге общения является признаком продвинутости, особой свободы и успешности”.

По факту же только один факт – в самом начале блокировок от Роскомнадзора, к Телеграм-клиенту пришёл патч размером где-то в 30 мегабайт. Основной тезис про обновления выглядел так – “в новую версию добавили улучшения связанные с пуш-уведомлениями, для обхода блокировки”. Кто-то вообще проверял, так ли это? Реально механизм пуш-уведомлений (он, кстати, в клиенте уже был) потребовал такого масштабного добавления программного кода? Размер обновления – больше дистрибутива Windows 95. Кто-то проверял, а не было ли что-то “слишком очевидное” удалено из клиентской части таким обновлением?

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

Чистая психология, а в сухом остатке – вроде и исходники есть, вроде и продукт открытый, а информации о том, что по факту – ровно столько же, сколько если бы он был официально “закрытым”.

Видел ли кто-то, кстати, альтернативный Телеграм-клиент, который бы не представлял собой клон достаточно старого исходника с изменениями в UI? (см. склад подобных вот тут)?

К примеру – если декларируется, что end-to-end шифрование в secret chat’ах никак не читается сервером – можно ведь взять исходник клиента и добавить ещё один уровень безопасности, дополнительно шифруя блок отдаваемой на сервер информации ключом, согласуемым через другое приложение. Идея очевидна, но почему-то не реализована.

Безопасно?

Ну, а это каждый решает для себя.

Это же всего лишь вопросы, правда?

Которым уже не первый месяц, если что.

И нуль ответов на оные со стороны декларирующих себя вроде-как-разбирающимися-в-безопасности юзерами телеграма. Как странно выходит – т.е. репостить ртом лозунги “Телеграм супербезопасен ибо супербезопасен все так считают поэтому нет смысла обсуждать” – у всех выходит, а чуть в конкретику углубление – какие-то панические “вывсёврёётииииии” и “нет смысла обсуждать ибо против Свободы” выскакивают.

В итоге, с тезисами вида

Павел разработал прорывной уникальный продукт, с лучшей и неуязвимой схемой защиты сессий пользователей, и технически не может отдать ключи, ведь это невозможно, ибо аббревиатуры E2E-шифрование и DH, а дальше нет смысла объяснять

вышло, скажем честно, не очень. Да, такие аббревиатуры и технологии есть, и их можно называть вслух как заклинания, гордясь сопричастностью к хайтеху. Можно даже флаг сделать – “Диффи и Хеллман прийде, порядок наведе, безопасность принесе”.

Вопрос о том, как они реализованы в данном конкретном продукте.

Всё зависит от того, с какой стороны зеркала ты стоишь.

Вернуться к полному списку статей Knowledge Base @ Advanced Training

Ruslan V. Karmanov

Зайдите на сайт под своей учётной записью, чтобы видеть комментарии под техническими статьями. Если учётной записи ещё нет - зарегистрируйтесь, это бесплатно.