Secure Storage (bezpieczne przechowywanie) — zespół metod i technologii ochrony poufnych danych na urządzeniu: tokenów, kluczy szyfrujących, informacji płatniczych i danych osobowych użytkowników. Według OWASP Mobile Top 10 (2024), niebezpieczne przechowywanie danych znajduje się w pierwszej trójce najpoważniejszych zagrożeń. Prawidłowa implementacja bezpiecznego przechowywania zapobiega wyciekom danych nawet przy fizycznym dostępie do urządzenia.
Najważniejsze
Secure Storage — praktyka przechowywania poufnych danych aplikacji mobilnej w taki sposób, aby były niedostępne dla innych aplikacji, złośliwego oprogramowania i atakującego przy fizycznym dostępie do urządzenia. W przeciwieństwie do zwykłego przechowywania, Secure Storage wykorzystuje szyfrowanie, izolację i ochronę sprzętową.
Nie wszystkie dane wymagają Secure Storage: obrazy profilowe czy pamięć podręczna wiadomości mogą być przechowywane w zwykłym systemie plików. Jednak klucze szyfrujące, tokeny uwierzytelniające, dane płatnicze, klucze prywatne i szablony biometryczne muszą być chronione. Według Google Security Blog (2025), 67% podatności w aplikacjach mobilnych związanych jest z przechowywaniem sekretów w otwartej postaci.
Każda platforma mobilna udostępnia własne mechanizmy Secure Storage: Android — Keystore i EncryptedSharedPreferences, iOS — Keychain i Data Protection API. Mechanizmy te są zintegrowane ze sprzętowymi modułami bezpieczeństwa (TEE, Secure Enclave) i gwarantują, że dane nie mogą być odczytane nawet po jailbreaku lub rootowaniu urządzenia.
Właściwy wybór metody Secure Storage zależy od rodzaju danych, scenariusza użycia i wymagań dotyczących wydajności. Zrozumienie architektury każdego mechanizmu pozwala programiście podjąć właściwą decyzję architektoniczną.
Platforma Android udostępnia kilka poziomów ochrony danych, od sprzętowego magazynu kluczy po zaszyfrowane SharedPreferences. Wybór zależy od wrażliwości danych i wymagań dotyczących wydajności.
Android Keystore — dostawca kryptograficzny generujący i przechowujący klucze w izolowanym środowisku wykonawczym (TEE — Trusted Execution Environment) na urządzeniach z obsługą ochrony sprzętowej. Klucze nigdy nie opuszczają TEE: operacje kryptograficzne są wykonywane wewnątrz chronionego obszaru, niedostępnego nawet dla systemu operacyjnego.
Od Androida 9 (API 28) Keystore obsługuje StrongBox Keymaster — dedykowany chip bezpieczeństwa z własnym CPU, True Random Number Generator (TRNG) i chronioną pamięcią. StrongBox jest certyfikowany zgodnie z Common Criteria EAL 4+ i stanowi najbezpieczniejszy poziom przechowywania kluczy na Androidzie. Aby użyć StrongBox, należy jawnie wskazać flagę inStrongBox() przy generowaniu klucza.
Keystore obsługuje algorytmy: AES/GCM/NoPadding (256 bitów), EC (secp256r1, secp384r1), RSA (2048–4096 bitów) i HMAC-SHA256. Wszystkie klucze mogą być powiązane z uwierzytelnianiem biometrycznym poprzez setUserAuthenticationRequired(true).
EncryptedSharedPreferences — biblioteka z pakietu AndroidX Security, która automatycznie szyfruje wszystkie dane zapisywane przez API SharedPreferences. Wartości są szyfrowane kluczem AES-256 GCM, a klucze — AES-256 SIV (syntetyczny IV), co zapobiega atakom słownikowym na nazwy kluczy.
Główny klucz szyfrujący jest przechowywany w Android Keystore, zapewniając ochronę dwupoziomową: Keystore chroni klucz główny, EncryptedSharedPreferences chroni dane. Wydajność szyfrowania wynosi poniżej 5 ms na operację odczytu/zapisu dla typowych danych (token, ustawienia), co czyni bibliotekę odpowiednią do scenariuszy użytkownika.
EncryptedSharedPreferences nie jest przeznaczona do dużych ilości danych (powyżej 5 MB) — w takich przypadkach należy użyć zaszyfrowanej bazy danych przez SQLCipher lub Room z szyfrowaniem.
SQLCipher — rozszerzenie SQLite, które szyfruje całą bazę danych stronicowo z użyciem AES-256-CBC. Każda strona bazy danych jest szyfrowana oddzielnym kluczem pochodnym od hasła głównego przez PBKDF2. SQLCipher dodaje około 5–15% narzutu wydajnościowego w zależności od rozmiaru danych.
Integracja z Androidem odbywa się przez bibliotekę net.zetetic:android-database-sqlcipher, która udostępnia API zgodne ze standardowym SQLiteOpenHelper. Hasło do SQLCipher zaleca się przechowywać w Keystore, a nie w kodzie lub SharedPreferences.
Platforma iOS udostępnia Keychain Services — główny bezpieczny magazyn, oraz Data Protection API do szyfrowania plików na poziomie systemu operacyjnego.
Keychain — zaszyfrowana baza danych SQLite, w której iOS przechowuje hasła, klucze szyfrujące, certyfikaty i notatki. Każdy element Keychain (SecItem) jest przechowywany w zaszyfrowanej postaci z użyciem sprzętowego klucza unikalnego dla urządzenia. Dostęp do elementu jest kontrolowany przez ACL (Access Control List), który może wymagać uwierzytelniania biometrycznego (Face ID, Touch ID) lub kodu dostępu.
Keychain obsługuje klasy ochrony (Protection Class) określające, kiedy dane są dostępne: kSecAttrAccessibleWhenUnlockedThisDeviceOnly — dane dostępne tylko przy odblokowanym urządzeniu i nieprzenoszone podczas kopii zapasowej. Ta klasa jest zalecana dla większości scenariuszy przechowywania tokenów uwierzytelniających.
Na iOS 15+ dostępny jest Security framework z obsługą sprzętowych kluczy przez Secure Enclave — dedykowany procesor Apple, który przetwarza operacje kryptograficzne i przechowuje klucze prywatne w izolowanej pamięci. Secure Enclave obsługuje algorytmy ECDSA (secp256r1) i ECDH do generowania kluczy, których nie można wyodrębnić z chipa.
Data Protection — mechanizm iOS szyfrujący każdy plik na poziomie systemu plików (APFS) z użyciem klucza powiązanego z kodem dostępu urządzenia. Deweloper określa poziom ochrony przez atrybut NSFileProtectionType przy tworzeniu pliku: NSFileProtectionComplete — plik dostępny tylko przy odblokowanym urządzeniu.
Data Protection działa automatycznie na wszystkich urządzeniach z iOS 5+, jeśli ustawiony jest kod dostępu. Szyfrowanie jest wykonywane na poziomie sprzętowym przez Dedicated AES Engine procesora Apple, co zapewnia wysoką wydajność — opóźnienie szyfrowania jest praktycznie niezauważalne dla użytkownika. Aby włączyć ochronę w aplikacji, wystarczy ustawić atrybut ochrony przy tworzeniu pliku przez FileManager.
Data Protection nie zastępuje Keychain do przechowywania kluczy — służy do szyfrowania plików, baz danych Core Data i innych dużych ilości danych. Kombinacja Keychain (dla kluczy) i Data Protection (dla plików) zapewnia pełny cykl bezpiecznego przechowywania na iOS.
Rozważmy praktyczne przykłady Secure Storage z użyciem wbudowanych API Androida i iOS.
Przykład pokazuje inicjalizację EncryptedSharedPreferences z kluczem głównym z Android Keystore. Wszystkie kolejne operacje odczytu i zapisu są automatycznie szyfrowane i deszyfrowane.
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
prefs.edit()
.putString("auth_token", "eyJhbGciOiJIUzI1NiJ9...")
.apply()
Przykład demonstruje zapisywanie i odczytywanie danych z iOS Keychain z użyciem Security framework. Kod wykorzystuje kSecAttrAccessibleWhenUnlockedThisDeviceOnly dla maksymalnej ochrony.
import Security
func saveToKeychain(key: String, data: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data,
kSecAttrAccessible as String:
kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
func readFromKeychain(key: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let status = SecItemCopyMatching(
query as CFDictionary, &result
)
return status == errSecSuccess ? result as? Data : nil
}
Przykład połączenia z zaszyfrowaną bazą SQLite przez SQLCipher z hasłem przechowywanym w Android Keystore.
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SQLiteOpenHelper
class SecureDBHelper(context: Context) :
SQLiteOpenHelper(context, "secure.db", null, 1) {
private val password = getKeyFromKeystore()
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE tokens (id INTEGER PRIMARY KEY, value TEXT)")
}
override fun onUpgrade(
db: SQLiteDatabase, oldVersion: Int, newVersion: Int
) {
onCreate(db)
}
}
// Użycie: podaj hasło przy otwieraniu
val helper = SecureDBHelper(context)
val db = helper.getWritableDatabase(password)
Prawidłowe użycie Secure Storage wymaga przestrzegania kilku fundamentalnych zasad, które zapobiegają typowym błędom programistów.
Określ klasyfikację danych: które dane wymagają ochrony sprzętowej (Keystore / Secure Enclave), które — szyfrowania na poziomie systemu operacyjnego (EncryptedSharedPreferences / Data Protection), a które można przechowywać w zwykłym systemie plików. Tokeny uwierzytelniające, klucze prywatne i dane płatnicze — tylko poziom sprzętowy. Ustawienia użytkownika (motyw, język) — wystarczy EncryptedSharedPreferences. Dane sesji (tymczasowe pamięci podręczne) mogą być przechowywane w pamięci lub katalogu tymczasowym.
Nigdy nie przechowuj sekretów w kodzie: ciągi z kluczami API, hasłami lub frazami seed w kodzie źródłowym to najpoważniejszy błąd bezpieczeństwa. Każdy reverse engineering natychmiast ujawni te dane. Używaj Keystore dla kluczy, a do konfiguracji — zdalne ładowanie przy uruchomieniu aplikacji (remote config).
Używaj powiązania biometrycznego dla krytycznych operacji: Android Keystore i iOS Keychain obsługują powiązanie kluczy z uwierzytelnianiem biometrycznym. Przy każdym dostępie do klucza system prosi o Face ID, Touch ID lub biometrię Androida (BiometricPrompt). Gwarantuje to, że nawet przy pełnej kontroli nad urządzeniem atakujący nie będzie mógł użyć zapisanych danych bez właściciela.
Testuj ochronę: używaj narzędzi analizy bezpieczeństwa — MobSF (Mobile Security Framework) do analizy statycznej, objection do testów runtime i Frida do omijania zabezpieczeń. Sprawdzaj, czy dane są niedostępne po rootowaniu lub jailbreaku. Android umożliwia sprawdzenie obecności roota przez SafetyNet Attestation lub Play Integrity API, iOS — przez weryfikację integralności Secure Enclave.
Regularnie aktualizuj biblioteki kryptograficzne: podatności w bibliotekach szyfrujących są wykrywane regularnie. Śledź CVE dla AndroidX Security, SQLCipher i wrapperów Keychain. Wdróż system automatycznych powiadomień o nowych wersjach przez Dependabot lub Renovate.
Według Apple Security Research (2025), prawidłowa implementacja Secure Storage zapobiega 96% ataków mających na celu kradzież danych z urządzenia. Pozostałe 4% — ataki z fizycznym dostępem i exploity dnia zerowego, przeciwko którym skuteczne jest powiązanie biometryczne.
Często zadawane pytania
iOS Keychain — zaszyfrowana baza danych do przechowywania haseł, kluczy i certyfikatów z kontrolą dostępu przez ACL. Android Keystore — dostawca kryptograficzny generujący i przechowujący klucze w izolowanym środowisku (TEE/StrongBox), który nie pozwala na wyodrębnienie klucza prywatnego.
EncryptedSharedPreferences używa AES-256 GCM do szyfrowania wartości i AES-256 SIV do szyfrowania kluczy. Główny klucz jest przechowywany w Android Keystore, zapewniając ochronę dwupoziomową. Dodatkowo używany jest HMAC-SHA256 do weryfikacji integralności.
Tak, HTTPS chroni dane tylko w kanale transmisji. Na urządzeniu dane są przechowywane w otwartej postaci po deszyfrowaniu. Jeśli atakujący uzyska fizyczny dostęp do urządzenia lub zainstaluje złośliwe oprogramowanie, HTTPS nie ochroni zapisanych danych. Zawsze szyfruj dane na poziomie przechowywania.
Użyj Android Keystore z flagą setUnlockedDeviceRequired(true), która blokuje dostęp do kluczy na zrootowanych urządzeniach. Dodatkowo sprawdzaj integralność przez Play Integrity API, a w przypadku odchyleń od wartości referencyjnych czyść wszystkie sekrety z magazynu.
Nie, UserDefaults przechowuje dane w otwartej postaci w pliku plist w piaskownicy. Każda aplikacja z narzędziami reverse engineeringu (przez kopię zapasową lub jailbreak) może odczytać tokeny. Tylko Keychain — jedyne bezpieczne miejsce do przechowywania sekretów na iOS.
Podsumowanie
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.
Przeczytaj również