Сегодня расскажу о том, чем мы с коллегами заняты уже несколько месяцев: о пуш-уведомлениях для мобильных мессенджеров. Как я уже говорил, в нашем приложении главный упор сделан на безопасность. Поэтому мы выясняли, есть ли у пуш-уведомлений “слабые места” и если да, то как мы можем их нивелировать, чтобы добавить эту полезную опцию в наш сервис.
Публикую перевод нашей статьи с Medium с небольшими добавлениями от себя. В ней итоги “расследования” и рассказ о том, как решили проблему.
Исследуем матчасть
В классической модели пуш-уведомления делают мессенджеры уязвимыми для атак MITM (Man-in-the-middle, «Человек посередине»). Например, у Google, Microsoft и в старой версии iMessage приложение отправляет ключи шифрования на серверы Apple — на сервере происходит аутентификация пользователей и дешифровка заголовка сообщения (либо его содержания).
В итоге есть шанс прочесть переписку, получив доступ к серверу пуш-уведомлений. А это значит, что любые шифрования переписки бесполезны: пуш-уведомления все равно оставят возможность для чтения третьими лицами. Подробнее эту возможность обсуждали авторы статьи “Шифруйся грамотно” на Xaker.ru, посвященной способам шифрования сообщений.
Если вам кажется, что серверы Apple и Google 100% не допустят утечки ключей шифрования пользователей, подумайте о том, что к ним имеют доступ их сотрудники. А сотрудники — люди.
При всех уязвимостях пушей, многие «безопасные» мессенджеры, включая Signal и Telegram, используют их. Ведь иначе пользователям придется «вручную» мониторить новые сообщения, постоянно заходя в приложение. Что весьма неудобно, и мессенджеры-конкуренты получат преимущество.
Паранойя и здравый смысл
В нашем проекте мы вплотную занялись этим вопросом несколько месяцев назад. Нам нужно было сделать опцию пуш-уведомлений, чтобы быть конкурентоспособными. Но при этом не провертеть дыру в безопасности, потому что любая утечка данных подорвет доверие к проекту.
Впрочем, у нас уже есть важное преимущество: наш мессенджер децентрализованный (данные хранятся в блокчейне), при этом сотрудники не имеют доступа к учетным записям. Ключи шифрования есть только у пользователей, а публичные ключи собеседников доступны в блокчейне, чтобы защитить от MITM-атак.
В первой версии пушей мы решили максимально перестраховаться и вообще не передавать текст сообщения. Пуш-сервис получал от ноды не текст сообщения, а только сигнал о факте его получения. Поэтому пользователь видел уведомление «Пришло новое сообщение». Прочесть его было возможно только в мессенджере.
Как это работало: видео.
После этого мы узнали, что в последней версии уведомлений от Apple есть новые элементы защиты. Они выпустили UNNotificationServiceExtension, который позволяет разработчикам отправлять полностью зашифрованные данные уведомлений через APNS. Затем приложение на устройстве конечного пользователя выполняет расшифровку (или загружает дополнительные данные) и отображает уведомление. Ее мы и взяли за основу второй версии пушей.
Сейчас мы разработали вторую версию пуш-уведомлений для iOS, которая позволяет отображать текст сообщения без угрозы безопасности. В новой концепции логика выглядит так:
- Пуш сервис отправляет push-уведомление с номером транзакции (шифрованное сообщение может быть очень большим, а размер уведомлений сильно ограничен)
- Устройство при получении уведомления запускает наш NotificationServiceExtension — микроприложение, которое запрашивает у ноды транзакцию по id, расшифровывает с помощью сохранённой пассфразы, и отдаёт системе новое уведомление. Пассфраза хранится в безопасном хранилище.
- Система показывает уведомление с расшифрованным сообщением или переводом.
- Ключи никуда не уходят, как и plain text-сообщение. У пуш-сервиса нет возможности расшифровать сообщение.
Эту версию мы приняли за рабочую и реализовали в последнем обновлении приложения для iOS.
Интересующиеся технической стороной могут посмотреть исходный код: github.com/Adamant-im/adamant-notificationService.
Комментарии (6)
canister_exister
20.06.2019 18:37Раз уж пошли скриншоты из андройда, то можно еще и про андройд чутка?
JustDeveloper Автор
20.06.2019 18:43Скриншоты Андроида — это просто примеры пушей популярных мессенджеров. Мы сделаем пуш-уведомления и для нашего приложения для Андроид, но это следующий этап разработки! Раз интересна эта тема, то как сделаем релиз — расскажу.
apes_aping_apes
20.06.2019 20:52Что-то вы долго соображали. Мы с коллегами пришли к этому решению за два дня. Из неприятного — у вас есть 30 секунд на получение и расшифровку сообщения, чего, разумеется, достаточно для большинства случаев, но оставляет место для рисков.
omaksim
22.06.2019 14:45Почему передаётся только id, а не сам текст сообщения (зашированный)? Зачем лишний шаг с запросом на сервер? Это должно сильно влиять на скорость работы и особенно на энергоэффективность устройства пользоватея. iOS такие «жадные» service extensions активно ограничивает – не запускает вообще после достижения довольно строгих лимитов.
iWheelBuy
Можно было написать что-нибудь про UNNotificationServiceExtension. Как его дебажили, как справлялись с нехваткой памяти и т.п.
JustDeveloper Автор
Хм, а это вариант! Попробую. Надеюсь, хватит на полноценную статью.