EncryptedSharedPreferences: co to jest, API i jak używać

Autor: IT Sectr Opublikowano: 2026-03-14 Czas czytania: 10 min

EncryptedSharedPreferences — to komponent biblioteki AndroidX Security, zapewniający przezroczyste szyfrowanie danych zapisywanych przez API SharedPreferences. W przeciwieństwie do zwykłych SharedPreferences, gdzie dane są przechowywane w otwartym pliku XML, EncryptedSharedPreferences automatycznie szyfruje klucze i wartości przed zapisem na dysk. Według Android Developers, biblioteka używa AES-256 GCM dla wartości i AES-256 SIV (RFC 5297) dla kluczy, zapewniając poufność i integralność danych.

Najważniejsze

  • EncryptedSharedPreferences — otoczka wokół SharedPreferences z automatycznym szyfrowaniem wszystkich zapisywanych danych
  • Szyfrowanie używa AES-256 GCM dla wartości i AES-256 SIV dla kluczy przez Android Keystore
  • Authenticated Encryption (AEAD) gwarantuje, że dane nie zostały zmienione po zapisie
  • Master Key jest przechowywany w Android Keystore i chroniony sprzętowo na urządzeniach z TEE
  • API w pełni kompatybilne z SharedPreferences — wymiana następuje bez zmiany kodu odczytu i zapisu

Czym jest EncryptedSharedPreferences?

EncryptedSharedPreferences — to klasa z pakietu androidx.security.crypto, wprowadzona w AndroidX Security 1.0.0 (2019). Implementuje interfejs SharedPreferences, ale wszystkie operacje zapisu (putString, putInt, putBoolean itd.) wstępnie szyfrują dane, a operacje odczytu odszyfrowują je przed zwróceniem.

Problem zwykłych SharedPreferences

Standardowe SharedPreferences zapisują dane w pliku XML w katalogu aplikacji (/data/data/package/shared_prefs/). Plik nie jest zaszyfrowany — przy root dostępie do urządzenia lub analizie kopii zapasowej wszystkie dane są czytelne jako zwykły XML. Tokeny uwierzytelniania, klucze API, dane osobowe użytkownika stają się dostępne dla atakującego.

EncryptedSharedPreferences rozwiązuje ten problem na poziomie biblioteki: dane są szyfrowane przed zapisem na dysk i odszyfrowywane przy odczycie. Deweloper nie musi ręcznie wywoływać funkcji kryptograficznych — API pozostaje identyczne jak w zwykłych SharedPreferences.

Historia i wersje

Biblioteka AndroidX Security v1.0.0 została wydana w grudniu 2019. EncryptedSharedPreferences zastąpiła przestarzałe podejście z ręcznym szyfrowaniem przez Cipher + SharedPreferences. Obecna stabilna wersja to 1.1.0-alpha06 (2024), obsługująca API 19+. Biblioteka wchodzi w skład Jetpack i nie wymaga dodatkowych uprawnień.

Według Google Security Blog (2024), EncryptedSharedPreferences to zalecany sposób przechowywania poufnych ustawień aplikacji, które nie wymagają synchronizacji przez chmurę. Dla bardziej złożonych scenariuszy zaleca się Room z szyfrowaniem przez SQLCipher.

Jak działa EncryptedSharedPreferences?

EncryptedSharedPreferences używa dwupoziomowego schematu szyfrowania: klucz główny (Master Key) jest przechowywany w Android Keystore, a do szyfrowania danych używane są klucze pochodne. To połączenie ochrony Keystore i wydajności szyfrowania symetrycznego.

Schemat szyfrowania: AES-256 GCM + SIV

Dla wartości używany jest AES-256 GCM (Galois/Counter Mode) — tryb uwierzytelnionego szyfrowania (AEAD), zapewniający poufność i integralność danych. Dla kluczy (nazw parametrów) stosuje się AES-256 SIV (RFC 5297) — deterministyczne szyfrowanie, niezbędne do wyszukiwania po kluczu bez ujawniania jego zawartości.

Każdy plik EncryptedSharedPreferences zawiera zaszyfrowane pary klucz-wartość. Struktura pliku: najpierw nagłówek z metadanymi (wersja, identyfikator klucza), następnie lista zaszyfrowanych wpisów. Plik nie jest prawidłowym XML i nie jest czytelny w edytorach tekstowych.

MasterKey i KeyStore

Klasa MasterKey odpowiada za tworzenie i zarządzanie 256-bitowym kluczem głównym, który jest przechowywany w Android Keystore. MasterKey.Builder pozwala skonfigurować: typ przechowywania (Keystore lub programowy), ochronę biometrią, czas życia klucza. Domyślnie klucz główny jest generowany w Android Keystore z algorytmem AES/GCM/NoPadding.

kotlin
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
    )
}

Konfiguracja szyfrowania

EncryptedSharedPreferences.create przyjmuje pięć parametrów: kontekst, nazwę pliku, klucz główny, schemat szyfrowania kluczy i schemat szyfrowania wartości. Wybór schematów wpływa na wydajność i poziom ochrony.

Schematy szyfrowania kluczy

AES256_SIV — szyfrowanie deterministyczne: identyczne klucze zawsze dają identyczny zaszyfrowany tekst. Jest to niezbędne do wyszukiwania po kluczu (SharedPreferences.getX(key)). Wadą jest to, że atakujący może określić, które klucze są używane, po powtarzających się szyfrogramach. AES256_SIV2 — ulepszona wersja z dodatkową randomizacją.

Dla wartości używany jest AES256_GCM. GCM dodaje 12-bajtowy IV (wektor inicjalizacyjny) i 16-bajtowy znacznik uwierzytelniający do każdej wartości. Zapewnia to poufność (nikt nie odczyta wartości) i uwierzytelnienie (nikt nie podmieni wartości bez wykrycia).

Ochrona biometryczna klucza głównego

Metoda setUserAuthenticationRequired(true) w MasterKey.Builder wymaga potwierdzenia biometrycznego przed uzyskaniem klucza głównego z Keystore. Dodaje to dodatkowy poziom: nawet jeśli aplikacja jest uruchomiona na odblokowanym urządzeniu, atakujący nie odczyta EncryptedSharedPreferences bez Face ID lub Touch ID.

Ważne: przy setUserAuthenticationRequired klucz główny staje się niedostępny, jeśli użytkownik zmienił lub usunął biometrię. Należy obsługiwać KeyPermanentlyInvalidatedException i utworzyć nowy klucz główny z migracją danych.

kotlin
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) {
        // Biometria się zmieniła — trzeba ponownie utworzyć klucz
    }
}

Przykład użycia w Kotlin

Rozważmy pełny przykład integracji EncryptedSharedPreferences w aplikacji Android w Kotlin. Biblioteka androidx.security:security-crypto jest dodawana przez Gradle.

Dodawanie zależności

W pliku build.gradle (app) dodaj: implementation "androidx.security:security-crypto:1.1.0-alpha06". Dla projektów Kotlin wymagany jest również kotlin-stdlib. Inicjalizacja MasterKey odbywa się jednorazowo, zwykle w Application.onCreate lub przez kontener DI.

Odczyt i zapis danych

Po utworzeniu instancji EncryptedSharedPreferences API nie różni się od zwykłych SharedPreferences. edit() zwraca Editor, wszystkie metody (putString, getString, putBoolean, getBoolean) działają analogicznie. Różnica jest tylko wewnątrz: dane są szyfrowane przy zapisie i odszyfrowywane przy odczycie.

kotlin
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()
    }
}

Migracja ze zwykłych SharedPreferences

Do migracji istniejących danych z niezabezpieczonych SharedPreferences do EncryptedSharedPreferences należy: odczytać wszystkie dane ze starego pliku, utworzyć nowy EncryptedSharedPreferences, zapisać wszystkie dane, usunąć stary plik. Google nie udostępnia wbudowanego narzędzia migracji — deweloper implementuje je samodzielnie.

Porównanie ze zwykłymi SharedPreferences

Wybór między SharedPreferences a EncryptedSharedPreferences zależy od rodzaju przechowywanych danych. Dla ustawień interfejsu (motyw, język, sortowanie) zwykłe SharedPreferences są wystarczające. Dla poufnych informacji (tokeny, hasła, klucze) EncryptedSharedPreferences jest obowiązkowy.

Wydajność

EncryptedSharedPreferences jest wolniejsze od zwykłych z powodu operacji kryptograficznych. Zapis pojedynczej wartości tekstowej trwa ~5-15 ms (zależy od rozmiaru danych i sprzętowego przyspieszenia AES). Odczyt — 2-5 ms. Dla większości aplikacji jest to niezauważalne, ale przy operacjach wsadowych (migracja, przywracanie) warto używać apply() zamiast commit().

Bezpieczeństwo

Zwykłe SharedPreferences nie zapewniają żadnej ochrony kryptograficznej: plik XML może być odczytany przez każdy proces z root dostępu lub przez adb backup. EncryptedSharedPreferences szyfruje dane na poziomie aplikacji, a klucz główny jest przechowywany w Android Keystore z możliwością ochrony sprzętowej (StrongBox).

CechaSharedPreferencesEncryptedSharedPreferences
PrzechowywanieOtwarty XMLZaszyfrowany plik binarny
SzyfrowanieBrakAES-256 GCM + SIV
Ochrona kluczyBrakAndroid Keystore + StrongBox
Wydajność0.1-1 ms2-15 ms
ZalecenieUstawienia UITokeny, klucze, PII

Kiedy wybrać EncryptedSharedPreferences

Używaj EncryptedSharedPreferences do przechowywania: refresh token OAuth, kluczy API dla zewnętrznych serwisów, adresu email lub numeru telefonu użytkownika, poufnych ustawień aplikacji (PIN, flagi uwierzytelniania). Do przechowywania danych biometrycznych lub dużych dokumentów EncryptedSharedPreferences nie nadaje się — użyj EncryptedFile lub Room z SQLCipher.

Ogólna zasada: jeśli dane po wycieku zaszkodzą użytkownikowi lub firmie — używaj EncryptedSharedPreferences. Jeśli dane są tylko kosmetyczne (motyw, język, sortowanie) — zwykłe SharedPreferences. EncryptedSharedPreferences ma sens wdrażać od razu, bez refaktoryzacji: zastąpienie w istniejącym projekcie wymaga migracji i obsługi starych niezaszyfrowanych danych.

Pamiętaj, że EncryptedSharedPreferences nie chroni danych podczas pracy aplikacji — tylko na dysku. Jeśli atakujący ma dostęp do pamięci procesu, odszyfrowane dane mogą zostać przechwycone. Używaj dodatkowej ochrony: ProGuard/DexGuard do zaciemniania kodu.

Często zadawane pytania

Czym EncryptedSharedPreferences różni się od DataStore?

Jetpack DataStore — to nowocześniejsza alternatywa dla SharedPreferences, oparta na Flow i Kotlin coroutines. DataStore domyślnie nie szyfruje danych, ale może być połączony z EncryptedSharedPreferences lub używany z ręcznym szyfrowaniem przez Proto DataStore z protokołami kryptograficznymi.

Czy można używać EncryptedSharedPreferences dla dużych woluminów danych?

Nie zaleca się. EncryptedSharedPreferences jest przeznaczony dla małych woluminów (do 100-200 KB). Do większych danych używaj Room z SQLCipher lub szyfrowania plików przez EncryptedFile z tej samej biblioteki AndroidX Security.

Czy EncryptedSharedPreferences obsługuje migrację przy aktualizacji schematu?

Nie, automatyczna migracja schematu nie istnieje. Przy zmianie struktury danych deweloper musi ręcznie odczytać stare dane przez stary KeyGen i zapisać je przez nowy. Zaleca się przechowywanie wersji schematu w osobnym parametrze.

Jaki jest minimalny wymagany poziom API?

AndroidX Security 1.0.0 obsługuje API 19+ (Android KitKat). Wersja 1.1.0-alpha06 również obsługuje API 19+. Do korzystania z StrongBox wymagane jest API 28+ i urządzenie z obsługą sprzętową (Google Pixel 3+, Samsung Galaxy S9+).

Czy przechowywanie refresh token w EncryptedSharedPreferences jest bezpieczne?

Tak, refresh token — to jeden z głównych scenariuszy użycia. Szyfrowanie AES-256 GCM, klucz główny w Keystore, ochrona biometryczna — wystarczający poziom dla tokenów OAuth. Dla access token z krótkim czasem życia również jest odpowiedni, choć niektóre zespoły preferują przechowywanie go w pamięci.

Podsumowanie

  • EncryptedSharedPreferences — otoczka SharedPreferences z automatycznym szyfrowaniem przez AES-256 GCM (wartości) i SIV (klucze)
  • Master Key tworzony przez MasterKey.Builder i przechowywany w Android Keystore z opcjami biometrii i StrongBox
  • API w pełni kompatybilne: edit, putString, getString, apply, clear — wszystko jak w zwykłych SharedPreferences
  • Wydajność: 2-15 ms na operację, co jest niezauważalne dla użytkownika przy standardowych scenariuszach
  • Bezpieczeństwo: uwierzytelnione szyfrowanie (AEAD) zapobiega zarówno odczytowi, jak i podmianie danych
  • Migracja ze zwykłych SharedPreferences wymaga ręcznego przeniesienia danych przez stary i nowy plik
  • Używaj EncryptedSharedPreferences do tokenów, kluczy API, haseł i innych poufnych ustawień

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również