Как я случайно взломал «несуществующую» базу данных и нашёл все приватные ключи в мессенджере с «эталонным» уровнем шифрования. Рассказ о подробном анализе Converso и развенчивании смелых заявлений разработчиков о том, что их продукт не собирает пользовательские данные, не отслеживает метаданные, не использует серверы и вообще является передовым решением в области конфиденциального обмена сообщениями, превосходящим всем известные WhatsApp, Telegram и Signal.
Недавно на подкасте услышал такую рекламу:
Я использую Converso из соображений конфиденциальности, потому что она для меня важна, и потому что другие мессенджеры, обещающие аналогичный сервис, рядом с Converso выглядят как NSA (National Security Agency, Агентство национальной безопасности США). Пользуясь Converso, вы получаете сквозное шифрование, отсутствие сбора данных пользователей и метаданных, плюс ваши сообщения не сохраняются на сервере.
Отсутствие метаданных? Это сильное и интригующее заявление. Даже Signal, представляющий золотой стандарт шифрования сообщений за счёт своих компонентов Double Ratchet и X3DH, всё равно умудряется допустить утечку кучи метаданных.
Разработчики также высказывают свои невероятные заявления на сайте и в платных интервью, поэтому мне стало любопытно, как они собираются реализовать все свои обещания. Вот небольшой отрывок из одного такого интервью.
Я принимал как должное, что мессенджеры со сквозным шифрованием не могут обойти тот факт, что при передаче зашифрованного сообщения от одного человека другому необходим посредник — процесс, неизбежно включающий метаданные, например то, с кем и когда вы ведёте диалог. Однако, если верить Converso, то их сообщения «минуют» сервер, не оставляя никаких следов.
Насколько мне известно, единственный способ исключить из этой схемы посредника — перейти от клиент-серверной модели к одноранговой модели клиент-клиент. Но эта идея имеет ряд проблем:
- Отправитель и получатель должны находиться в сети одновременно. Обмен сообщениями в режиме офлайн работать не будет, а возможность асинхронной отправки сообщений пользователю, находящемуся не в сети, в современных мессенджерах является необходимым требованием.
- Сторонам потребуется способ установки прямой связи друг с другом, но они обе наверняка будут работать через маршрутизаторы NAT. Как в таком случае им искать IP-адреса друг друга? (Существует метод hole punching, но он также опирается на стороннего участника, опосредующего соединение).
К сожалению, Converso не опенсорсный, и на сайте проекта нет никакой информации об используемых в нём криптографических примитивах и протоколах, что крайне странно для приложения, самопровозгласившего себя «эталоном» в области конфиденциальности. К сравнению, Signal, WhatsApp и Telegram открыто предоставляют подробные технические описания своих систем сквозного шифрования, которые тщательно тестируются и рецензируются сторонними экспертами. Разработчики же Converso утверждают, что ждут получения патентов и откроют исходный код после.
Единственным средством анализа внутреннего устройства их продукта остаётся реверс-инжиниринг или декомпиляция. Так что я заглянул в приложение Converso, чтобы протестировать механизм его работы и примерно сравнить используемый в нём новейший протокол шифрования с протоколами устоявшихся приложений-аналогов вроде Signal.
Скриншот conversoapp.com/about-us/
Прозрачность
К сожалению, честность в последнее время вышла из моды (спросите некоторых из наших конкурентов). Но мы всё ещё верим в устные договорённости, личную ответственность и способность людей выполнять обещанное. Никакого вранья — только прозрачное общение и эталонный уровень безопасности.
P. S. Мы откроем исходный код, как только закончим оформление всех патентов.
Скриншот с conversoapp.com
Вскрытие APK
Прежде чем открывать приложение, я решил заглянуть в его содержимое, вскрыв скачанный APK-файл.
Мне повезло, что приложение написано на JavaScript (React Native). Файл index.android.bundle
содержит весь его код и бо́льшую часть зависимостей – минимизированных для сокращения размера, но всё же читаемых.
Содержимое пакета Converso
Для начала я решил выяснить, на какие домены здесь есть ссылки.
Конфигурация Firebase
Первым делом я заметил, что разработчики включили в конфигурацию Firebase measurementId
, являющееся необязательным полем, которое добавляется для активации Google Analytics. В этом функционале нет ничего плохого, но он явно не должен присутствовать в приложении, которое полностью исключает использование данных пользователей.
Следующий интересный домен – это zekeseo.com. Похоже, что это другой сайт создателей Converso, предлагающий маркетинговые SEO-услуги. Странно видеть его здесь.
zekeseo.com добавлен в две функции
По сути, этот код говорит, что если выбранное вами имя пользователя не содержит символ @
, то приложение сделает его email-адресом, добавив в конце @zekeseo.com
. Думаю, что какой-то структуре – бэкенду – нужно, чтобы имена пользователей были представлены в формате email-адресов, а фронтенду нет.
Далее я обнаружил ссылку на URL с Pixabay. Им оказался резервный URL для аватара профиля пользователя. Не уверен, почему это должен быть внешний URL – похоже на ошибку.
Предустановленный аватар загружается с cdn.pixabay.com
Предустановленный аватар размещён на Pixabay.com
Поиск кода шифрования
Занявшись поиском криптографических примитивов, я нашёл ссылки на AES и RSA. Ожидал же я обнаружить эллиптическую криптографию, поскольку мне не известен ни один современный протокол, который бы не использовал ECC.
Как бы то ни было, но сообщения действительно шифруются — это очевидно по функциям encryptMessage
и decryptMessage
. Но это ещё не говорит о том, что шифрование серьёзное. Как именно они шифруются, как происходит генерация и обмен ключами, как часто эти ключи заменяются, как они и сообщения аутентифицируются, и как зашифрованные сообщения попадают от отправителя к получателю?
Рассматривая код вокруг некоторых из этих функций шифрования, я увидел ссылки на Seald
и API, размещённый на поддомене seald.io.
Это приложение использует Seald SDK
После открытия домашней страницы Seald многие вопросы отпали. Seald — это встраиваемый SDK, позволяющий интегрировать сквозное шифрование «в любое приложение в считаные минуты».
Теперь это очевидно: разработчики Converso не создавали никакого передового протокола шифрования. Они просто реализовали этот SDK. Приложение поручает обработку компонентов шифрования именно Seald.
Домашняя страница Seald
Но пока остаётся открыт вопрос о том, как Converso и используемый им Seald могут передавать сообщения без их сохранения на сервере и получения метаданных? Действительно ли Seald позволяет Converso делать столь смелые заявления?
К счастью, ответы на эти вопросы можно найти в документации Seald. Дальше изучать исходный код Converso необходимости нет.
Как на самом деле работает шифрование Converso — заявления и реальность
Когда вы отправляете сообщение другому пользователю Converso, происходит следующее:
- Отправитель получает с сервера Seald публичный RSA-ключ
Pk
, связанный с телефонным номером получателя, и регистрирует его как достоверный. - Отправитель шифрует своё сообщение
M
с помощью AES-256-CBC, используя кратковременный симметричный ключK
. - Отправитель шифрует
К
с помощью RSAES-OAEP так, чтобы его мог расшифровать только владелецPk
. - Отправитель создаёт MAC для аутентификации сообщения,
Mac
с HMAC-SHA-256. - Отправитель через сетевой запрос посылает на сервер
Mac
с открытым текстом, а также зашифрованные копииM
иK
. Затем сервер доставляет всё это получателю.
Вот, собственно, и всё.
Здесь не задействовано никакое одноранговое соединение — приложение использует классическую архитектуру клиент-сервер.
Теперь, когда мы разобрались с протоколом шифрования Converso, можно рассмотреть некоторые из заявлений, сделанных на сайте продукта, сопоставив их с реальностью.
Обновление (2023-05-13): с момента публикации этой статьи разработчики Converso удалили многие из своих заявлений. Приведённые далее дословные цитаты ранее присутствовали на сайте Converso или в официальных маркетинговых материалах.
▍ Заявление: «Эталонное сквозное шифрование»
Вердикт: ложь.
Скриншот с conversoapp.com/about-us/
Безопасность
Благодаря нашей проприетарной передовой технологии шифрования, все ваши собеседники, сообщения и вызовы полностью защищены и не могут быть перехвачены никем и никогда.
Для того, чтобы стандарт шифрования считался «передовым», он должен как минимум включать все возможности современных протоколов шифрования. В Converso же используется простой RSA, один из старейших доступных стандартов.
Начнём с генерации случайных чисел — здесь всё неплохо. В качестве источника случайности для генерации безопасных ключей на устройствах Android в Converso используется java.security.SecureRandom
, а в iOS — CSPRNG.
Следующий момент. Как Converso защищается от атак по принципу «человек посередине»? Для этого должна быть возможность убедиться в том, что вы ведёте беседу именно с тем, с кем предполагаете, а не с подставным человеком или посредником. В этом Converso опирается на сторонние средства — в частности, серверы Seald — выступающие единственным удостоверяющим центром, отвечающим за сопоставление сущностей с публичными ключами.
Этот сторонний ресурс имеет все возможности, чтобы выдать себя за кого угодно. В Converso нет ничего вроде чисел безопасности, которые бы обеспечивали целостность зашифрованной беседы — в этом приложении нет функции для просмотра публичного ключа вашего контакта, а также отсутствуют уведомления в случае изменения такого ключа. Это серьёзная недоработка.
Примечание (2023-05-17): хочу уточнить, что я не ставлю под вопрос безопасность Seald. Эта компания не бросается теми же обещаниями, которые создатели Converso делают относительно своего сквозного протокола шифрования. Прекрасно задокументированные протоколы Seald отлично подходят для многих случаев, но не для мессенджера со сквозным шифрованием, который сравнивает себя с Signal, WhatsApp, Telegram и Viber. Кроме того, некоторые из этих недоработок, такие как отсутствие защиты от атак «человек посередине», являются результатом слабой реализации SDK.
Далее разберём целостность сообщений и аутентификацию. Есть ли гарантии, что в процессе передачи сообщение не было изменено, и как можно убедиться, что оно действительно поступило от конкретного отправителя? Поскольку все публичные ключи априори являются ненадёжными, ни о какой серьёзной аутентификации сообщений говорить уже не приходится.
Forward secrecy (прямая секретность)? Отсутствует. В отличие от устоявшихся мессенджеров с шифрованием, с которыми себя сравнивает Converso, в случае взлома устройства с этим приложением грамотный злоумышленник сможет использовать находящиеся на нём ключи для расшифровки последних бесед, даже если они были с этого устройства удалены. Жизненный цикл асимметричных пар ключей в Seald по умолчанию составляет три года (к сравнению, аналогичные пары в Signal Protocol заменяются с каждым сообщением).
Future secrecy (безопасность после компрометирования)? В современных мессенджерах с шифрованием реализована возможность самовосстановления, которая не позволяет атакующему расшифровать последующие сообщения после компрометирования устройства. В Converso также попробовали этот функционал реализовать.
Результаты:
Функционал | Converso | Signal и пр. |
Какой-то вид шифрования | Да | Да |
Защита от атак «человек посередине» | Нет | Да |
Аутентификация сообщений | Нет | Да |
Прямая секретность | Нет | Да |
Безопасность после компрометирования | Нет | Да |
▍ Заявление: «Никаких серверов», «Никакого сохранения сообщений на серверах»
Вердикт: ложь.
В Converso заявляют, что не используют серверы
Никаких серверов
Управление беседами (включая ваши контакты) происходит только на вашем устройстве.
Сообщения и ключи передаются на сервер и доставляются им же. Естественно, серверы присутствуют.
▍ Заявление: «Никакого использования пользовательских данных», «Никакого отслеживания», «Когда вы используете Converso, никакие ваши данные не сохраняются ни на наших серверах, ни где-либо ещё»
Вердикт: ложь.
Скриншот conversoapp.com/faqs/
Сохраняет ли Converso какие-либо из моих данных?
Нет. Когда вы используете Converso, никакие из ваших данных не сохраняются ни на наших серверах, ни где-либо ещё.
Converso не только включает трекер Google Analytics для регистрации использования приложения, но также собирает номера телефонов каждого аккаунта плюс неизбежные метаданные каждого отправляемого/получаемого сообщения или ключа. Все эти данные хранятся на серверах.
Кроме того, предположительно по ошибке разработчиков, каждый пользователь Converso отправляет HTTP-запрос на cdn.pixabay.com для скачивания предустановленного аватара. Согласно политике конфиденциальности Pixabay, эта платформа регистрирует такие запросы вместе с IP-адресами и деталями совершающих их устройств.
Заявление Converso, что сообщения не оставляют за собой никаких метаданных, абсолютно ложно, включая и более конкретные утверждения вроде:
Устройство, с которого вы совершаете доступ [скрыто].
Когда вы используете приложение, ваш IP-адрес, а также местоположение и детали устройства, передаются в Seald, Google Analytics и Pixabay.
Ваша личность [скрыта].
Для регистрации требуется номер телефона, который сохраняется на сервере.
Личность вашего собеседника [скрыта].
Сообщения адресуются на телефонные номера и доставляются через серверы. Сервер должен знать получателя каждого сообщения, чтобы перенаправлять это сообщение на нужное устройство. То есть он знает, кто вы, а также с кем и когда общаетесь.
▍ Заявление: «Сквозное шифрование платформы обойти невозможно», «Каждое отправленное сообщение имеет сквозное шифрование, то есть может быть прочитано только предполагаемым получателем»
Вердикт: ложь.
Как было показано выше, используемый в Converso протокол шифрования является устаревшим и уязвим ко многим видам атак.
Поскольку пары ключей совершенно ненадёжны, при использовании Converso нет никакой гарантии безопасности. Его протокол шифрования опирается на доверенного стороннего посредника, всегда действующего честно.
▍ Заявление: «Основатель WhatsApp также основал Signal»
Вердикт: ложь.
Скриншот с converso.com
Не принадлежит жадному на пользовательские данные Facebook и был запущен тем же человеком, который основал WhatsApp.
Facebook приобрёл WhatsApp в 2014 году за $19 миллиардов. При этом основатель WhatsApp также основал Signal.
Сооснователь WhatsApp был причастен к созданию фонда, который сейчас занимается разработкой Signal, но это произошло через 8 лет после запуска мессенджера. То есть этот фонд фактически не является Signal.
Signal был выпущен в 2014 году компанией Open Whisper Systems, принадлежащей Мокси Марлинспайк, однако до этого ещё с 2010 года он существовал в виде TextSecure. В 2018 году Брайан Актон, сооснователь WhatsApp, помог запустить некоммерческий фонд Signal Technology Foundation, чьей целью стала «поддержка и продвижение миссии Signal по расширению доступности и повсеместности конфиденциальной коммуникации».
▍ Заявление: «WhatsApp, Telegram и Viber [...] хранят сообщения (в читаемом формате) на серверах»
Вердикт: ложь или сильное искажение фактов.
Скриншот с conversoapp.com/converso-security/
Отсутствие хранения сообщений на серверах
В отличие от WhatsApp, Telegram и Viber, которые хранят сообщения (в читаемом формате) на серверах (то есть в облаке), при отправке через Converso сообщения сохраняются только на устройстве получателя. Вы также можете установить их самоуничтожение или удаление на обоих устройствах, спустя определённый промежуток времени.
В WhatsApp и Viber реализован Signal Protocol, а в зашифрованных беседах Telegram используется MTProto. Оба этих решения являются широко известными и хорошо задокументированными протоколами шифрования, которые были тщательно проанализированы сторонними исследователями.
Зашифрованные сообщения не сохраняются в читаемом виде на серверах WhatsApp, Telegram или Viber. В Telegram сквозное шифрование является опциональной функцией — стандартные незашифрованные сообщения попадают на сервер.
Со стороны Converso также звучало заявление, что WhatsApp генерирует незашифрованные резервные копии чатов в Google Cloud и iCloud, но это не совсем так. Резервные копии WhatsApp являются опциональными и могут быть защищены сквозным шифрованием (хотя пока по умолчанию этого не происходит).
▍ Заявление: «Каждая беседа, происходящая на нашей платформе, является частью децентрализованной архитектуры»
Вердикт: ложь.
В Converso для передачи ключей и сообщений используются центральные серверы. Это приложение не имеет децентрализованной архитектуры — в нём задействуется традиционная клиент-серверная модель.
▍ Заявление: «[Signal] реализует распределение данных блокчейна через Amazon S3»
Вердикт: ложь или сильное искажение фактов.
В Signal есть поддержка одноранговых платежей в «MobileCoin», приватной криптовалюте, но этот функционал является дополнительным и не особо популярным. Стандартные сообщения Signal со сквозным шифрованием не используют MobileCoin или какой-либо другой вид данных блокчейна.
Короткий вывод
Как это часто бывает, не всей информации в сети можно верить. Converso в ложном свете представляет себя как передовой мессенджер со сквозным шифрованием, что очень далеко от истины. По факту эти смелые утверждения, включающие обещания высочайшего уровня безопасности, а также попытки бросить тень на ведущие протоколы шифрования, на поверку все оказываются ложными. Поэтому я считаю, что вам не следует рассматривать Converso как инструмент, способный обеспечить серьёзный уровень безопасности, и уж тем более платить за него по $4,95/месяц.
Скриншот conversoapp.com/download-converso/
Как долго Converso будет бесплатным?
Все уровни Converso останутся абсолютно бесплатными до 1 августа 2023 года. После этого мы выпустим несколько планов: бесплатный (до 75 звонков и сообщений в месяц), стоимостью $2,95 (неограниченное использование) и $4,95 (неограниченное использование + дополнительные возможности).
Но подождите — на деле всё ещё хуже
Уже заканчивая эту статью, я заметил в коде Converso нечто странное, что упустил ранее. В нём присутствует куча ссылок на функции, которые, по всей видимости, связаны с базой данных Google Firestore.
Ранее в коде я видел использование SQLite для некоторых более простых операций, таких как индексирование адресных книг локальных устройств. Тогда я предположил, что SQLite также используется и для других задач, вроде обработки сообщений, и что серверы задействуются только для передачи данных, а не в качестве длительного хранилища — но ошибся.
Часть кода SQLite, обнаруженного ранее (выявляем дополнительную уязвимость)
Похоже, что Firestore является фреймворком для работы с базами данных, используемым Converso для хранения всевозможных данных приложения, включая отправленные и полученные сообщения, журналы вызовов, регистрационные данные пользователей и, возможно, другие виды пользовательского контента.
Базы данных Firestore для 'chats' и 'messages'
Меня это шокировало и даже сбило с толку, поскольку Firestore является облачной базой данных, управляемой Google. Это не интерфейс внутренней базы данных, работающей исключительно офлайн, который, предположительно, должно использовать подобное приложение. И похоже, что Firestore используется для большого количества данных, которые явно должны обрабатываться офлайн. В коде я вижу коллекции и подколлекции Firestore с названиями users
, chats
, messages
, missedCalls
, videoInfo
, recents
, rooms
, fcmTokens
, phoneRooms
, phoneInfo
, usersPublic
, loginError
, callerCandidates
и calleeCandidates
.
▍ Но ведь база данных Firestore однозначно защищена, не так ли?
В случае любой онлайн-базы данных мы ожидаем наличие на стороне сервера правил доступа, защищающих чувствительные данные.
Я решил попробовать использовать учётные данные Firebase, которые ранее нашёл в коде приложения, чтобы убедиться в подобающей защите данных правилами безопасности Firebase. Одних только учётных данных не должно быть достаточно для получения неограниченного доступа к чувствительной информации этой БД.
Я написал небольшой код, чтобы проверить, удастся ли мне получить данные из коллекции
users
:
initializeApp({
apiKey: "AIzaSyBBswl_VaCb7h7nIj8xBhreuxj2NH6aqis",
authDomain: "converso-448da.firebaseapp.com",
projectId: "converso-448da",
storageBucket: "converso-448da.appspot.com",
messagingSenderId: "1025894877514",
appId: "1:1025894877514:web:58f4a74a44071f727c19b3"
});
const db = getFirestore();
const querySnapshot = await getDocs(collection(db, "users"));
И вот, что я получил:
Небольшая часть коллекции users
Похоже, я случайно взломал базу данных пользователей Converso. Коллекция users
, которая находится в открытом доступе, содержит детали регистрации каждого пользователя Converso. Номера телефонов, временны́е метки регистрации, а также идентификаторы групп, в которых пользователи состоят (то есть кто и с кем общается).
Многие из этих коллекций базы данных точно так же оказались полностью открытыми. Для доступа к коллекциям fcmTokens
, loginError
, missedCalls
, phoneInfo
, phoneRooms
, rooms
, usersPublic
и videoPublic
не требуется какой-либо аутентификации пользователей на стороне сервера.
Если вы не знакомы с Firestore, то эта ошибка, по сути, равнозначна развёртыванию открытой для интернета базы данных SQL, не требующей для доступа имени пользователя и пароля — любой может читать и записывать в неё всё, что угодно.
▍ Метаданные Converso являются открытыми
Converso не только собирает и сохраняет большие объёмы метаданных, существование которых отрицает, но эти метаданные ещё и оказываются открытыми. Если вы совершите звонок, эта информация окажется доступна для всего мира, и её сможет в реальном времени просмотреть любой интересующийся.
Эти данные сохраняются в незашифрованном виде на серверах Google — очень иронично для бизнес-проекта, который в своих маркетинговых заявлениях выступает против «технологических гигантов», в том числе Google.
«Converso создан для людей, которые ищут полной конфиденциальности и свободы от любой формы слежки, будь то правительство или технологические гиганты».
Скриншот conversoapp.com/converso-security/
Децентрализованная архитектура
Каждая беседа, происходящая на нашей платформе, является частью децентрализованной архитектуры. При такой архитектуре беседы списки пользователей и группы сохраняются на устройствах пользователей. Это означает, что ваша информация будет существовать только на вашем устройстве, а не на центральных серверах, принадлежащих AWS, Google или Apple.
▍ Анализ остальных коллекций Firestore
Коллекция rooms
содержит метаданные, связанные с сеансами видеозвонков. Видео- и аудиопотоки между пользователями работают через WebRTC.
Небольшая часть коллекции rooms
Аналогичным образом phoneRooms
содержит метаданные совершаемых в приложении аудиовызовов.
Небольшая часть коллекции phoneRooms
Коллекция fcmTokens
содержит длинный список токенов регистрации FCM для каждого пользователя. Они представляют собой идентификаторы, выдаваемые серверами подключения GCM для того, чтобы клиенты могли получать уведомления и прочие виды относящихся к приложению сообщений.
Не уверен, как именно эти токены используются в Converso, но документация Firebase отчётливо гласит: «токены регистрации должны держаться в секрете».
Небольшая часть коллекции fcmTokens
Мне не удалось получить доступ к коллекциям chats
и messages
— похоже, здесь, наконец, используется некая схема разрешений. Не уверен, какие тут работают правила безопасности — возможно, я дополню материал на эту тему позднее. Вернёмся к коду.
▍ Онлайн-база данных сообщений Converso
В Converso есть две категории сообщений: открытые и зашифрованные. И те, и другие хранятся в коллекции Firestore messages
, размещённой на серверах Google. Вот пример того, как выглядят их записи:
{
createdAt: <timestamp>,
number: "<sender phone number>",
message: "<cleartext message>",
encryptedMessage: "<encrypted message>",
messageContent: "<i don't know what this is yet>",
tokens: ["<i don't know what this is yet>"],
selfDestruct: <time-to-live>, // optional
}
Следующие категории сообщений Converso вообще не шифруются:
- Изображения. Это записи сообщений с
isImage: true
и открытым полемimageName
, содержащим имя файла изображения. Эти файлы передаются в незашифрованном виде через сервис Firebase Cloud Storage. - Анимированные сообщения. Записи этих сообщений содержат дополнительные поля
url
иisGif: true
. Когда устройство получает подобное сообщение, оно автоматически скачивает объект по его ссылке без каких-либо вопросов и отключить это нельзя. Очевидно, что здесь возникает серьёзная уязвимость: при желании можно легко получить IP-адрес любого пользователя Converso, просто отправив сообщение, указывающее на URL, принадлежащий отправителю. - Запросы на очистку (clear) истории сообщений беседы. Записи этих открытых сообщений содержат
isClear: true
. - Запросы на удаление (delete) предыдущего сообщения. Записи этих открытых сообщений содержат
isDelete: true
и полеmessageId
, указывающее сообщение для удаления. - Уведомления о скриншоте. Если приложение обнаруживает, что был сделан скриншот, оно отправляет открытое сообщение с текстом
"Screenshot taken"
и значениемisScreenshot: true
.
Зашифрованные сообщения, которые содержат в своих записях Firestore строку encryptedMessage
, передаются в Seald SDK для расшифровки функцией decryptMessage
. Эта функция преобразует шифротекст в формате base64 в простую текстовую строку, используя метод шифрования, описанный выше.
Вызов функции Seald decryptMessage
▍ Более детальный разбор «зашифрованных» сообщений
В ходе дальнейшего инспектирования связанного с Seald кода я заметил, что в Converso используется модуль @seald-io/sdk-plugin-ssks-password
. Согласно документации разработчиков, он позволяет Converso использовать «защищённое устройство для хранения ключей» с целью «удобного и безопасного хранения учётных данных, зашифрованных паролем пользователя».
Значит закрытые ключи резервируются на серверах Seald, зашифрованные паролями пользователей. Если пользователь удаляет приложение Converso, он может позднее восстановить свой суперсекретный ключ RSA, запросив зашифрованную версию с сервера и расшифровав её локально с помощью пароля. После восстановления ключа пользователь сможет расшифровать старые сообщения, хранящиеся в базе данных Firestore.
Но здесь есть серьёзная проблема: в Converso нет такого понятия, как пароль. Для создания учётной записи вам достаточно ввести номер телефона и верифицировать его через SMS-код. Если же пароля не существует, то чем тогда шифруются ключи?
Этот код шифрует секретные ключи пользователя паролем и загружает их в бэкап-сервис Seald
Сложновато отследить, откуда в этом минимизированном коде JS берётся переменная пароля (u). Время использовать декомпилятор, чтобы сделать код более понятным.
$ npx react-native-decompiler -i ./index.android.bundle -o ./output
Теперь будет проще отслеживать переменные между функциями. Стало очевидно, что рассматриваемый мной код находится внутри компонента React Native под названием Seald
.
Теперь код стал более понятен
Эта переменная содержит пароль для шифрования
Оказывается, что имя пользователя Seald является телефонным номером пользователя, а пароль шифрования — это просто его ID. Очень плохо. То есть пароли для шифрования — это ID пользователей Firebase, которые являются открытыми.
У меня уже есть список телефонных номеров всех пользователей и их ID, которые я скачал ранее из открытой коллекции users
. Это означает, что сейчас я располагаю учётными данными для скачивания и расшифровки любого закрытого ключа Converso, дающего возможность расшифровать любое сообщение.
Короткий скрипт для подтверждения этого открытия с помощью официального Seald SDK:
Использование учётных данных Seald из кода приложения совместно с телефонным номером пользователя и его ID из открытой базы данных Converso
$ node test.js
[19:29:17.328 04/05/2023 UTC+10] info :seald-sdk - Seald SDK - Start
[19:29:17.338 04/05/2023 UTC+10] info :goatee - Instantiating Goatee
[19:29:17.341 04/05/2023 UTC+10] info :goatee - Initializing goatee
[19:29:18.993 04/05/2023 UTC+10] info :seald-sdk - Already initialized
[19:29:19.028 04/05/2023 UTC+10] info :goatee - Setting new default user...
[19:29:23.590 04/05/2023 UTC+10] info :goatee/database/models/User - Sigchain updated for user 2yXXXXXXXXXXXLEw. Sigchain matches with db: true
good password!
Достаточно. На этом я закончу своё тестирование, так как уже нахожусь в одном шаге от серьёзного нарушения чьей-то личной тайны путём прочтения сообщения, которое должно быть зашифрованным и конфиденциальным.
▍ Закрытые ключи тоже по факту открыты
Открытыми оказались не только метаданные, но и ключи, используемые для шифрования сообщений. Любой может скачать закрытый ключ пользователя Converso и использовать его для расшифровки секретных бесед.
Больше нет никакого явного различия между открытыми и зашифрованными сообщениями — никакого серьёзного шифрования. В целях собственной безопасности вам не следует использовать Converso для отправки каких-либо сообщений, которые вы бы не стали публиковать в соц. сетях.
История кейса
Об этих вопиющих уязвимостях я сообщил разработчикам Converso до момента публикации статьи.
- 2023-05-05: Сообщил об уязвимостях Converso. Пост подготовлен.
- 2023-05-05: Ответ Converso: «Благодарим вас за отклик и уделённое этому вопросу время. Я передал всю информацию нашим CEO и CTO, и мы непременно займёмся решением этих проблем. Ожидайте подробного ответа в ближайшее время».
- 2023-05-05: Вопрос Converso: «Как вы смогли декомпилировать исходный код приложения и что, на ваш взгляд, следует сделать для его защиты от подобного в будущем?»
- 2023-05-05: Мой ответ: «Ваше приложение разработано с помощью React Native. Просто переименуйте файл APK в .7z и извлеките файл
assets/index.android.bundle
. Он содержит собранный исходный код Converso и соответствующие зависимости JavaScript. Тут не от чего защищаться — в других приложениях всё аналогично. Кроме того, даже если вы сможете усложнить этот процесс, всегда будет небезопасно опираться на обеспечение защиты сервера со стороны клиента». - 2023-05-05: Вопрос Converso: «Можете сообщить нам, что вы делаете и где находитесь? Спасибо».
- 2023-05-06: Converso: «Хотим сообщить вам, что развернули новую версию и ожидаем одобрения этой сборки. Мы продолжим работать над обновлениями, опираясь на вашу обратную связь, за которую вам очень признательны».
- 2023-05-06: В Apple одобрили новую версию их приложения для iOS. В заметках релиза представители Converso сообщают, что в новой версии «были устранены незначительные баги», и «реализованы более продвинутые решения для системы безопасности».
- 2023-05-06: Google одобряет новую версию приложения для Android.
- 2023-05-09: Converso: «Уязвимость, касающаяся правил Firebase, была исправлена, и мы предлагаем вам её протестировать. Ещё одна уязвимость, связанная с ключами шифрования, была устранена путём реализации на нашей стороне, и мы ожидаем получения новых учётных данных, чтобы текущие пользователи прошли повторную аутентификацию. Тем не менее все существующие сообщения, отправленные со старыми ключами шифрования, защищены правилами Firebase, поэтому не могут быть прочитаны третьими лицами».
- 2023-05-10: В Converso ещё раз благодарят меня за привлечение их внимания к уязвимостям. Статья опубликована.
- С 2023-05-11 по 2023-05-12: Основатель Converso, Таннер Хаас, сообщает мне, что у него и его «команды юристов» есть претензии к моей статье, в связи с чем они рекомендуют её удалить. Он отправляет мне серию писем, обвиняя в дискредитации и утверждая, что я «либо сотрудник [Signal], либо сам Мокси». В то же время они начинают удалять содержимое с сайта и маркетинговые материалы, включая бо́льшую часть ложных и искажающих истину утверждений, процитированных в этой статье.
- 2023-05-14: Converso публикует на сайте новую статью, по всей видимости, с целью опередить в поисковых системах эту и, возможно, другие, указывающие на пробелы в их системе безопасности и представление сервиса в ложном свете. В метаописание их статьи включена фраза «проверка заявлений Converso».
- 2023-05-16: Приложение Converso больше недоступно для скачивания в Google Play Store и iOS App Store. Пока не понятно, почему, и вернётся ли оно туда. Либо Converso намеренно прекратили распространение своего продукта, либо к нему возникли вопросы со стороны самих магазинов.
- 2023-05-16: В отправленном мне e-mail представитель Converso подтверждает, что они добровольно исключили своё приложение из магазинов на время «исправления проблем».
Автор: Дмитрий Брайт