Перейти к основному содержанию
Блог

Мобильные

Безопасное хранение чувствительных данных в мобильном приложении: Keystore и Keychain

Хранение токенов и персональных данных в SharedPreferences или UserDefaults экспертиза считает высоким риском. Как правильно использовать Android Keystore и iOS Keychain.

· 6 мин. чтения

Фото: The Cleveland Trust Company An Epitome of the Past, A Chron, Public domain · Wikimedia Commons

Одна из Android-находок в экспертизе нашего собственного приложения была короткой и точной: «чувствительные данные хранятся во внутреннем хранилище без шифрования». Уровень риска — высокий. Приложение хранило токен доступа в обычном файле настроек. На обычном телефоне другое приложение этот файл прочитать не может, но на рутованном устройстве или через резервную копию он виден открытым текстом.

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

Типичная ошибка: «внутреннее хранилище и так закрыто»

Многие разработчики рассуждают так: папка приложения находится в песочнице, другие приложения туда не попадут, значит, шифровать не обязательно. Это верно только в идеальных условиях. На практике данные из внутреннего хранилища могут утечь так:

  • Root или jailbreak — пользователь с максимальными правами может прочитать папку любого приложения.
  • Резервная копия — если на Android включён allowBackup, данные приложения попадают в резервную копию и могут быть восстановлены на другом устройстве.
  • Физический доступ и форензика — если устройство попало в чужие руки, открыто сохранённые данные извлечь проще.
  • Другая уязвимость в приложении — например, WebView или content provider с неправильным доступом к файлам.

Поэтому группа STORAGE в MASVS требует хранить чувствительные данные в защищённых механизмах платформы. В OWASP Mobile Top 10 2024 это категория M9 (Insecure Data Storage).

Что считается чувствительным

  • Токены доступа (access) и обновления (refresh), идентификаторы сессий.
  • API-ключи и ключи шифрования.
  • Персональные данные: ПИНФЛ, паспортные данные, номер телефона, финансовые показатели.
  • Данные, связанные с биометрией или PIN-кодом.

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

Инструменты платформы

Android Keystore

Android Keystore — система хранения криптографических ключей. Её главное преимущество: ключ не попадает в память приложения. На многих устройствах ключ хранится на аппаратном уровне (TEE или StrongBox). Приложение просит зашифровать данные ключом, но сам ключ не видит. Зашифрованные данные могут лежать в обычном файле — без ключа они бесполезны.

iOS Keychain

iOS Keychain — системное зашифрованное хранилище для паролей, токенов и ключей. Для каждой записи задаётся условие доступа. Например:

  • WhenUnlockedThisDeviceOnly — данные читаются только когда устройство разблокировано и не переносятся на другое устройство через резервную копию.
  • AfterFirstUnlockThisDeviceOnly — данные доступны после первой разблокировки после перезагрузки. Удобно для фоновых запросов.

Суффикс ThisDeviceOnly важен: он не даёт записи перенестись на другое устройство через резервную копию iCloud.

На практике во Flutter: flutter_secure_storage

В нашем Flutter-приложении мы использовали пакет flutter_secure_storage. На Android он использует шифрование на основе Keystore, на iOS — Keychain, а код один для обеих платформ:

const storage = FlutterSecureStorage(
  iOptions: IOSOptions(
    accessibility: KeychainAccessibility.first_unlock_this_device,
  ),
);

await storage.write(key: 'access_token', value: token);
final token = await storage.read(key: 'access_token');

Вместе с этим были внесены следующие изменения:

  1. Все токены перенесены из SharedPreferences. SharedPreferences остался только для нечувствительных настроек: язык, тема, просмотрен ли онбординг.
  2. Резервное копирование отключено. В AndroidManifest.xml:
<application
    android:allowBackup="false"
    android:dataExtractionRules="@xml/data_extraction_rules">

data_extraction_rules управляет облачным резервным копированием и переносом между устройствами на Android 12 и выше.

  1. При выходе всё очищается. Когда пользователь выходит из системы, записи в защищённом хранилище удаляются, также очищаются кеш, cookie и сохранённые данные WebView. Иначе следующий пользователь может найти следы предыдущей сессии.

Защищённое хранилище защищает данные на диске. Но оно не защищает то, что приложение держит в памяти во время работы. Поэтому оно должно работать вместе с RASP и обнаружением root.

Тонкие моменты

  • iOS Keychain может сохраняться после удаления приложения. Если пользователь удалит и заново установит приложение, старый токен может найтись. Решение: при первом запуске проверяйте простой флаг и, если его нет, удаляйте старые записи из Keychain.
  • В логах не должно оставаться чувствительных данных. В release-сборке токены, тела запросов и персональные данные не должны писаться в лог.
  • Кеш и временные файлы. Скачанные документы, PDF-отчёты и изображения тоже могут быть чувствительными. Удаляйте их после использования.
  • Скриншоты. На чувствительных экранах можно использовать FLAG_SECURE на Android и скрывать содержимое на iOS при уходе приложения в фон.

Проверьте сами

  1. На рутованном тестовом устройстве откройте папку приложения (/data/data/<пакет>/) и поищите открытые токены или персональные данные в shared_prefs, базах данных и файлах.
  2. Проверьте, не утекают ли данные через adb backup или перенос устройства.
  3. Убедитесь, что после выхода из системы в папке приложения и данных WebView не остаётся следов сессии.
  4. На iOS удалите и заново установите приложение и проверьте, что автоматического входа не происходит.

Вывод

Безопасное хранение чувствительных данных — несложная задача: платформа даёт для этого готовые инструменты. Основная работа — выяснить, где хранятся данные, перенести их в Keystore или Keychain и правильно настроить резервное копирование и очистку при выходе.

Если хотите проверить, как ваше приложение хранит чувствительные данные, оставьте заявку на сканирование. Мы найдём уязвимости и поможем закрыть их до экспертизы.