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 είναι η συνιστώμενη μέθοδος αποθήκευσης εμπιστευτικών ρυθμίσεων εφαρμογής που δεν απαιτούν συγχρονισμό μέσω cloud. Για πιο σύνθετα σενάρια, προτείνεται το Room με κρυπτογράφηση μέσω SQLCipher.
EncryptedSharedPreferences χρησιμοποιεί ένα σχήμα κρυπτογράφησης δύο επιπέδων: το κύριο κλειδί (Master Key) αποθηκεύεται στο Android Keystore, και για την κρυπτογράφηση δεδομένων χρησιμοποιούνται παράγωγα κλειδιά. Αυτός είναι ένας συνδυασμός προστασίας Keystore και απόδοσης συμμετρικής κρυπτογράφησης.
Για τιμές χρησιμοποιείται AES-256 GCM (Galois/Counter Mode) — λειτουργία πιστοποιημένης κρυπτογράφησης (AEAD), που εξασφαλίζει εμπιστευτικότητα και ακεραιότητα δεδομένων. Για κλειδιά (ονόματα παραμέτρων) εφαρμόζεται AES-256 SIV (RFC 5297) — ντετερμινιστική κρυπτογράφηση, απαραίτητη για αναζήτηση βάσει κλειδιού χωρίς αποκάλυψη του περιεχομένου του.
Κάθε αρχείο EncryptedSharedPreferences περιέχει κρυπτογραφημένα ζεύγη κλειδιού-τιμής. Δομή αρχείου: πρώτα μια κεφαλίδα με μεταδεδομένα (έκδοση, αναγνωριστικό κλειδιού), στη συνέχεια μια λίστα κρυπτογραφημένων εγγραφών. Το αρχείο δεν είναι έγκυρο XML και δεν διαβάζεται από επεξεργαστές κειμένου.
Η κλάση MasterKey είναι υπεύθυνη για τη δημιουργία και διαχείριση του 256-bit κύριου κλειδιού, το οποίο αποθηκεύεται στο 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 προσθέτει ένα IV 12-byte (διάνυσμα αρχικοποίησης) και μια ετικέτα πιστοποίησης 16-byte σε κάθε τιμή. Αυτό εξασφαλίζει εμπιστευτικότητα (κανείς δεν μπορεί να διαβάσει την τιμή) και πιστοποίηση (κανείς δεν μπορεί να τροποποιήσει την τιμή χωρίς ανίχνευση).
Η μέθοδος 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 ms (ανάλογα με το μέγεθος των δεδομένων και την επιτάχυνση υλικού AES). Ανάγνωση — 2-5 ms. Για τις περισσότερες εφαρμογές, αυτό είναι απαρατήρητο, αλλά σε μαζικές λειτουργίες (μετεγκατάσταση, επαναφορά) αξίζει να χρησιμοποιείτε apply() αντί για commit().
Οι συνηθισμένες SharedPreferences δεν παρέχουν καμία κρυπτογραφική προστασία: το αρχείο XML διαβάζεται από οποιαδήποτε διεργασία με πρόσβαση root ή μέσω adb backup. Το EncryptedSharedPreferences κρυπτογραφεί δεδομένα σε επίπεδο εφαρμογής, και το κύριο κλειδί αποθηκεύεται στο Android Keystore με δυνατότητα προστασίας υλικού (StrongBox).
| Χαρακτηριστικό | SharedPreferences | EncryptedSharedPreferences |
|---|---|---|
| Αποθήκευση | Ανοιχτό XML | Κρυπτογραφημένο δυαδικό αρχείο |
| Κρυπτογράφηση | Όχι | AES-256 GCM + SIV |
| Προστασία κλειδιών | Όχι | Android Keystore + StrongBox |
| Απόδοση | 0.1-1 ms | 2-15 ms |
| Σύσταση | Ρυθμίσεις UI | Διακριτικά, κλειδιά, PII |
Χρησιμοποιήστε EncryptedSharedPreferences για αποθήκευση: refresh token OAuth, κλειδιών API για εξωτερικές υπηρεσίες, email ή αριθμού τηλεφώνου χρήστη, εμπιστευτικών ρυθμίσεων εφαρμογής (PIN, σημαίες ελέγχου ταυτότητας). Για αποθήκευση βιομετρικών δεδομένων ή μεγάλων εγγράφων, το EncryptedSharedPreferences δεν είναι κατάλληλο — χρησιμοποιήστε EncryptedFile ή Room με SQLCipher.
Γενικός κανόνας: εάν η διαρροή δεδομένων βλάπτει τον χρήστη ή την επιχείρηση — χρησιμοποιήστε EncryptedSharedPreferences. Εάν τα δεδομένα είναι μόνο καλλυντικά (θέμα, γλώσσα, ταξινόμηση) — συνηθισμένες SharedPreferences. Το EncryptedSharedPreferences έχει νόημα να εφαρμοστεί αμέσως, χωρίς αναδιάρθρωση: η αντικατάσταση σε υπάρχον έργο απαιτεί μετεγκατάσταση και επεξεργασία παλαιών μη κρυπτογραφημένων δεδομένων.
Θυμηθείτε ότι το EncryptedSharedPreferences προστατεύει δεδομένα μόνο στο δίσκο — όχι κατά τη λειτουργία της εφαρμογής. Εάν ο εισβολέας έχει πρόσβαση στη μνήμη της διεργασίας, τα αποκρυπτογραφημένα δεδομένα μπορεί να υποκλαπούν. Χρησιμοποιήστε πρόσθετη προστασία: ProGuard/DexGuard για συσκότιση κώδικα.
Συχνές Ερωτήσεις
Jetpack DataStore — είναι μια πιο σύγχρονη εναλλακτική για SharedPreferences, βασισμένη σε Flow και Kotlin coroutines. Το DataStore δεν κρυπτογραφεί δεδομένα από προεπιλογή, αλλά μπορεί να συνδυαστεί με EncryptedSharedPreferences ή να χρησιμοποιηθεί με μη αυτόματη κρυπτογράφηση μέσω Proto DataStore με κρυπτογραφικά πρωτόκολλα.
Δεν συνιστάται. Το EncryptedSharedPreferences προορίζεται για μικρούς όγκους (έως 100-200 KB). Για μεγάλα δεδομένα, χρησιμοποιήστε 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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης