EncryptedSharedPreferences — це компонент бібліотеки AndroidX Security, що забезпечує прозоре шифрування даних, які зберігаються через API SharedPreferences. На відміну від звичайних SharedPreferences, де дані зберігаються у відкритому XML-файлі, EncryptedSharedPreferences автоматично шифрує ключі та значення перед записом на диск. Згідно з Android Developers, бібліотека використовує AES-256 GCM для значень і AES-256 SIV (RFC 5297) для ключів, забезпечуючи конфіденційність та цілісність даних.
Головне
EncryptedSharedPreferences — це клас із пакета androidx.security.crypto, представлений в AndroidX Security 1.0.0 (2019). Він реалізує інтерфейс SharedPreferences, але всі операції запису (putString, putInt, putBoolean тощо) попередньо шифрують дані, а операції читання розшифровують їх перед поверненням.
Стандартні SharedPreferences зберігають дані у файл XML у каталозі додатка (/data/data/package/shared_prefs/). Файл не зашифрований — при root-доступі до пристрою або під час аналізу резервної копії всі дані читаються як звичайний XML. Токени автентифікації, ключі API, персональні дані користувача стають доступними зловмиснику.
EncryptedSharedPreferences вирішує цю проблему на рівні бібліотеки: дані шифруються перед записом на диск і розшифровуються під час читання. Розробнику не потрібно викликати криптографічні функції вручну — API залишається ідентичним звичайним SharedPreferences.
Бібліотека AndroidX Security v1.0.0 вийшла в грудні 2019 року. EncryptedSharedPreferences замінила застарілий підхід із ручним шифруванням через Cipher + SharedPreferences. Поточна стабільна версія — 1.1.0-alpha06 (2024), що підтримує API 19+. Бібліотека входить до складу Jetpack і не потребує додаткових дозволів.
За даними Google Security Blog (2024), EncryptedSharedPreferences — рекомендований спосіб зберігання конфіденційних налаштувань додатка, які не потребують синхронізації через хмару. Для більш складних сценаріїв пропонується Room із шифруванням через SQLCipher.
EncryptedSharedPreferences використовує дворівневу схему шифрування: мастер-ключ (Master Key) зберігається в Android Keystore, а для шифрування даних використовуються похідні ключі. Це поєднує захист Keystore і продуктивність симетричного шифрування.
Для значень використовується AES-256 GCM (Galois/Counter Mode) — режим автентифікованого шифрування (AEAD), що забезпечує конфіденційність та цілісність даних. Для ключів (імен параметрів) застосовується AES-256 SIV (RFC 5297) — детерміноване шифрування, необхідне для пошуку за ключем без розкриття його вмісту.
Кожен файл EncryptedSharedPreferences містить зашифровані пари ключ-значення. Структура файлу: спочатку заголовок із метаданими (версія, ідентифікатор ключа), потім список зашифрованих записів. Файл не є валідним XML і не читається текстовими редакторами.
Клас MasterKey відповідає за створення та керування 256-бітним мастер-ключем, який зберігається в Android Keystore. MasterKey.Builder дозволяє налаштувати: тип сховища (Keystore або програмний), захист біометрією, час життя ключа. За замовчуванням мастер-ключ генерується в Android Keystore з алгоритмом AES/GCM/NoPadding.
import androidx.security.crypto.MasterKey
import androidx.security.crypto.EncryptedSharedPreferences
fun getEncryptedPrefs() {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.AES256_GCM_SPEC)
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
EncryptedSharedPreferences.create приймає п'ять параметрів: контекст, ім'я файлу, мастер-ключ, схему шифрування ключів та схему шифрування значень. Від вибору схем залежить продуктивність та рівень захисту.
AES256_SIV — детерміноване шифрування: однакові ключі завжди дають однаковий зашифрований текст. Це необхідно для пошуку за ключем (SharedPreferences.getX(key)). Недолік: зловмисник може визначити, які ключі використовуються, за повторюваними шифротекстами. AES256_SIV2 — покращена версія з додатковою рандомізацією.
Для значень використовується AES256_GCM. GCM додає 12-байтовий IV (вектор ініціалізації) та 16-байтовий тег автентифікації до кожного значення. Це забезпечує конфіденційність (ніхто не прочитає значення) та автентифікацію (ніхто не підмінить значення без виявлення).
Метод setUserAuthenticationRequired(true) у MasterKey.Builder вимагає біометричного підтвердження перед отриманням мастер-ключа з Keystore. Це додає додатковий рівень: навіть якщо додаток запущено на розблокованому пристрої, зловмисник не зможе прочитати EncryptedSharedPreferences без Face ID або Touch ID.
Важливо: при setUserAuthenticationRequired мастер-ключ стає недоступним, якщо користувач змінив або видалив біометрію. Необхідно обробляти KeyPermanentlyInvalidatedException та створювати новий мастер-ключ з міграцією даних.
fun createBiometricKey(): MasterKey {
return MasterKey.Builder(context)
.setKeyScheme(MasterKey.AES256_GCM_SPEC)
.setUserAuthenticationRequired(true)
.setRequestStrongBoxBacked(true)
.build()
}
fun writeSecureToken(token: String) {
try {
prefs.edit().putString("auth_token", token).apply()
} catch (e: KeyPermanentlyInvalidatedException) {
// Біометрія змінилася — потрібно перестворити ключ
}
}
Розглянемо повний приклад інтеграції EncryptedSharedPreferences в Android-додатку на Kotlin. Бібліотека androidx.security:security-crypto підключається через Gradle.
У файл build.gradle (app) додайте: implementation «androidx.security:security-crypto:1.1.0-alpha06». Для Kotlin-проектів додатково потрібен kotlin-stdlib. Ініціалізація MasterKey відбувається одноразово, зазвичай в Application.onCreate або через DI-контейнер.
Після створення екземпляра EncryptedSharedPreferences API не відрізняється від звичайних SharedPreferences. edit() повертає Editor, усі методи (putString, getString, putBoolean, getBoolean) працюють аналогічно. Різниця лише всередині: дані шифруються при записі та розшифровуються при читанні.
class AuthRepository(context: Context) {
private val prefs = createEncryptedPrefs(context)
fun saveCredentials(login: String, password: String) {
prefs.edit()
.putString("login", login)
.putString("password", password)
.apply()
}
fun getToken(): String? {
return prefs.getString("auth_token", null)
}
fun clearAll() {
prefs.edit().clear().apply()
}
}
Для міграції існуючих даних із незахищених SharedPreferences в EncryptedSharedPreferences необхідно: прочитати всі дані зі старого файлу, створити новий EncryptedSharedPreferences, записати всі дані, видалити старий файл. Google не надає вбудованого мігратора — розробник реалізує його самостійно.
Вибір між SharedPreferences та EncryptedSharedPreferences залежить від типу даних, що зберігаються. Для налаштувань інтерфейсу (тема, мова, сортування) звичайні SharedPreferences достатні. Для конфіденційної інформації (токени, паролі, ключі) EncryptedSharedPreferences обов'язковий.
EncryptedSharedPreferences повільніший за звичайні через криптографічні операції. Запис одного рядкового значення займає ~5-15 мс (залежить від розміру даних та апаратного прискорення AES). Читання — 2-5 мс. Для більшості додатків це непомітно, але при пакетних операціях (міграція, відновлення) варто використовувати apply() замість commit().
Звичайні SharedPreferences не забезпечують жодного криптографічного захисту: файл XML читається будь-яким процесом із root-доступом або через adb backup. EncryptedSharedPreferences шифрує дані на рівні додатка, а мастер-ключ зберігається в Android Keystore з можливістю апаратного захисту (StrongBox).
| Характеристика | SharedPreferences | EncryptedSharedPreferences |
|---|---|---|
| Зберігання | Відкритий XML | Зашифрований бінарний файл |
| Шифрування | Немає | AES-256 GCM + SIV |
| Захист ключів | Немає | Android Keystore + StrongBox |
| Продуктивність | 0.1-1 мс | 2-15 мс |
| Рекомендація | Налаштування UI | Токени, ключі, PII |
Використовуйте EncryptedSharedPreferences для зберігання: refresh token OAuth, ключів API для зовнішніх сервісів, email або номера телефону користувача, конфіденційних налаштувань додатка (PIN, прапорці автентифікації). Для зберігання біометричних даних або великих документів EncryptedSharedPreferences не підходить — використовуйте EncryptedFile або Room із SQLCipher.
Загальне правило: якщо дані при витоку завдадуть шкоди користувачеві або бізнесу — використовуйте EncryptedSharedPreferences. Якщо дані лише косметичні (тема, мова, сортування) — звичайні SharedPreferences. EncryptedSharedPreferences має сенс впроваджувати одразу, без рефакторингу: заміна в існуючому проекті потребуватиме міграції та обробки старих незашифрованих даних.
Пам'ятайте, що EncryptedSharedPreferences не захищає дані під час роботи додатка — тільки на диску. Якщо зловмисник має доступ до пам'яті процесу, розшифровані дані можуть бути перехоплені. Використовуйте додатковий захист: ProGuard/DexGuard для обфускації.
Часті запитання
Jetpack DataStore — це більш сучасна альтернатива SharedPreferences, заснована на Flow та Kotlin корутинах. DataStore не шифрує дані за замовчуванням, але може бути скомбінований з EncryptedSharedPreferences або використовуватися з ручним шифруванням через Proto DataStore з криптографічними протоколами.
Не рекомендується. EncryptedSharedPreferences призначений для невеликих обсягів (до 100-200 КБ). Для великих даних використовуйте Room із SQLCipher або шифрування файлів через EncryptedFile із тієї ж бібліотеки AndroidX Security.
Ні, автоматичної міграції схеми немає. При зміні структури даних розробник повинен вручну прочитати старі дані через старий KeyGen та записати їх через новий. Рекомендується зберігати версію схеми в окремому параметрі.
AndroidX Security 1.0.0 підтримує API 19+ (Android KitKat). Версія 1.1.0-alpha06 також підтримує API 19+. Для роботи StrongBox потрібен API 28+ та пристрій з апаратною підтримкою (Google Pixel 3+, Samsung Galaxy S9+).
Так, refresh token — один з основних сценаріїв використання. Шифрування AES-256 GCM, мастер-ключ в Keystore, біометричний захист — достатній рівень для OAuth токенів. Для access token з коротким часом життя також підходить, хоча деякі команди віддають перевагу зберіганню його в пам'яті.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також