EncryptedSharedPreferences: Khái niệm, API và cách sử dụng

Tác giả: IT Sectr Đã đăng: 2026-03-14 Thời gian đọc: 10 phút

EncryptedSharedPreferences là một thành phần của thư viện AndroidX Security cung cấp khả năng mã hóa minh bạch dữ liệu được lưu thông qua API SharedPreferences. Không giống như SharedPreferences thông thường, nơi dữ liệu được lưu trữ trong tệp XML thuần túy, EncryptedSharedPreferences tự động mã hóa khóa và giá trị trước khi ghi vào đĩa. Theo Android Developers, thư viện sử dụng AES-256 GCM cho giá trị và AES-256 SIV (RFC 5297) cho khóa, đảm bảo tính bảo mật và toàn vẹn dữ liệu.

Những Điểm Chính

  • EncryptedSharedPreferences — một lớp bao bọc SharedPreferences với mã hóa tự động tất cả dữ liệu được lưu
  • Mã hóa sử dụng AES-256 GCM cho giá trị và AES-256 SIV cho khóa thông qua Android Keystore
  • Authenticated Encryption (AEAD) đảm bảo dữ liệu không bị thay đổi sau khi ghi
  • Master Key được lưu trữ trong Android Keystore và được bảo vệ bằng phần cứng trên các thiết bị có TEE
  • API hoàn toàn tương thích với SharedPreferences — việc thay thế diễn ra mà không cần thay đổi mã đọc và ghi

EncryptedSharedPreferences là gì?

EncryptedSharedPreferences là một lớp từ gói androidx.security.crypto, được giới thiệu trong AndroidX Security 1.0.0 (2019). Nó triển khai giao diện SharedPreferences, nhưng tất cả các thao tác ghi (putString, putInt, putBoolean, v.v.) đều mã hóa dữ liệu trước, và các thao tác đọc giải mã dữ liệu trước khi trả về.

Vấn đề với SharedPreferences thông thường

SharedPreferences tiêu chuẩn lưu dữ liệu vào tệp XML trong thư mục ứng dụng (/data/data/package/shared_prefs/). Tệp không được mã hóa — với quyền truy cập root vào thiết bị hoặc trong quá trình phân tích sao lưu, tất cả dữ liệu đều được đọc dưới dạng XML thuần túy. Token xác thực, khóa API và dữ liệu cá nhân của người dùng trở nên dễ dàng truy cập đối với kẻ tấn công.

EncryptedSharedPreferences giải quyết vấn đề này ở cấp thư viện: dữ liệu được mã hóa trước khi ghi vào đĩa và được giải mã khi đọc. Nhà phát triển không cần gọi thủ công các hàm mật mã — API vẫn giống hệt SharedPreferences thông thường.

Lịch sử và phiên bản

Thư viện AndroidX Security v1.0.0 được phát hành vào tháng 12 năm 2019. EncryptedSharedPreferences đã thay thế phương pháp mã hóa thủ công lỗi thời thông qua Cipher + SharedPreferences. Phiên bản ổn định hiện tại là 1.1.0-alpha06 (2024), hỗ trợ API 19+. Thư viện là một phần của Jetpack và không yêu cầu quyền bổ sung.

Theo Google Security Blog (2024), EncryptedSharedPreferences là phương pháp được khuyến nghị để lưu trữ các cài đặt ứng dụng nhạy cảm không yêu cầu đồng bộ hóa đám mây. Đối với các tình huống phức tạp hơn, Room với mã hóa SQLCipher được khuyến nghị.

EncryptedSharedPreferences hoạt động như thế nào?

EncryptedSharedPreferences sử dụng sơ đồ mã hóa hai cấp: Master Key được lưu trữ trong Android Keystore và các khóa dẫn xuất được sử dụng để mã hóa dữ liệu. Điều này kết hợp bảo vệ Keystore với hiệu suất của mã hóa đối xứng.

Sơ đồ mã hóa: AES-256 GCM + SIV

Đối với giá trị, AES-256 GCM (Chế độ Galois/Counter) được sử dụng — một chế độ mã hóa xác thực (AEAD) đảm bảo tính bảo mật và toàn vẹn dữ liệu. Đối với khóa (tên tham số), AES-256 SIV (RFC 5297) được áp dụng — mã hóa xác định cần thiết để tra cứu khóa mà không tiết lộ nội dung của nó.

Mỗi tệp EncryptedSharedPreferences chứa các cặp khóa-giá trị được mã hóa. Cấu trúc tệp bao gồm: đầu tiên là tiêu đề với siêu dữ liệu (phiên bản, định danh khóa), sau đó là danh sách các mục nhập được mã hóa. Tệp không phải là XML hợp lệ và không thể đọc bằng trình soạn thảo văn bản.

MasterKey và KeyStore

Lớp MasterKey chịu trách nhiệm tạo và quản lý khóa chính 256 bit được lưu trữ trong Android Keystore. MasterKey.Builder cho phép cấu hình: loại lưu trữ (Keystore hoặc phần mềm), bảo vệ sinh trắc học và thời gian tồn tại của khóa. Theo mặc định, khóa chính được tạo trong Android Keystore với thuật toán 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
    )
}

Thiết lập và cấu hình mã hóa

EncryptedSharedPreferences.create nhận năm tham số: ngữ cảnh, tên tệp, khóa chính, sơ đồ mã hóa khóa và sơ đồ mã hóa giá trị. Việc lựa chọn sơ đồ ảnh hưởng đến hiệu suất và mức độ bảo mật.

Sơ đồ mã hóa khóa

AES256_SIV — mã hóa xác định: các khóa giống hệt nhau luôn tạo ra bản mã giống nhau. Điều này cần thiết cho việc tra cứu khóa (SharedPreferences.getX(key)). Nhược điểm: kẻ tấn công có thể xác định khóa nào đang được sử dụng bằng cách so sánh các bản mã lặp lại. AES256_SIV2 — phiên bản cải tiến với tính ngẫu nhiên bổ sung.

Đối với giá trị, AES256_GCM được sử dụng. GCM thêm IV 12 byte (vector khởi tạo) và thẻ xác thực 16 byte cho mỗi giá trị. Điều này cung cấp tính bảo mật (không ai có thể đọc giá trị) và xác thực (không ai có thể giả mạo giá trị mà không bị phát hiện).

Bảo vệ khóa chính bằng sinh trắc học

Phương thức setUserAuthenticationRequired(true) trong MasterKey.Builder yêu cầu xác nhận sinh trắc học trước khi lấy khóa chính từ Keystore. Điều này thêm một lớp bảo vệ bổ sung: ngay cả khi ứng dụng đang chạy trên thiết bị đã mở khóa, kẻ tấn công không thể đọc EncryptedSharedPreferences mà không có Face ID hoặc Touch ID.

Quan trọng: với setUserAuthenticationRequired, khóa chính trở nên không khả dụng nếu người dùng thay đổi hoặc xóa dữ liệu sinh trắc học. Cần xử lý KeyPermanentlyInvalidatedException và tạo khóa chính mới với di chuyển dữ liệu.

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) {
        // Sinh trắc học đã thay đổi — cần tạo lại khóa
    }
}

Ví dụ sử dụng trong Kotlin

Hãy xem một ví dụ hoàn chỉnh về tích hợp EncryptedSharedPreferences trong ứng dụng Android sử dụng Kotlin. Thư viện androidx.security:security-crypto được thêm qua Gradle.

Thêm phụ thuộc

Trong tệp build.gradle (app), thêm: implementation “androidx.security:security-crypto:1.1.0-alpha06”. Đối với các dự án Kotlin, kotlin-stdlib cũng được yêu cầu. Khởi tạo MasterKey diễn ra một lần, thường là trong Application.onCreate hoặc thông qua vùng chứa DI.

Đọc và ghi dữ liệu

Sau khi tạo phiên bản EncryptedSharedPreferences, API không khác gì SharedPreferences thông thường. edit() trả về một Editor, tất cả các phương thức (putString, getString, putBoolean, getBoolean) hoạt động tương tự. Sự khác biệt duy nhất là bên trong: dữ liệu được mã hóa khi ghi và giải mã khi đọc.

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

Di chuyển từ SharedPreferences thông thường

Để di chuyển dữ liệu hiện có từ SharedPreferences không được mã hóa sang EncryptedSharedPreferences, cần: đọc tất cả dữ liệu từ tệp cũ, tạo EncryptedSharedPreferences mới, ghi tất cả dữ liệu và xóa tệp cũ. Google không cung cấp trình di chuyển tích hợp — nhà phát triển tự triển khai thủ công.

So sánh với SharedPreferences thông thường

Sự lựa chọn giữa SharedPreferences và EncryptedSharedPreferences phụ thuộc vào loại dữ liệu được lưu trữ. Đối với cài đặt giao diện (chủ đề, ngôn ngữ, sắp xếp), SharedPreferences thông thường là đủ. Đối với thông tin bảo mật (token, mật khẩu, khóa), EncryptedSharedPreferences là bắt buộc.

Hiệu suất

EncryptedSharedPreferences chậm hơn thông thường do các thao tác mật mã. Ghi một giá trị chuỗi duy nhất mất ~5-15 ms (tùy thuộc vào kích thước dữ liệu và tăng tốc phần cứng AES). Đọc mất 2-5 ms. Đối với hầu hết ứng dụng, điều này không đáng kể, nhưng đối với các thao tác hàng loạt (di chuyển, khôi phục), hãy sử dụng apply() thay vì commit().

Bảo mật

SharedPreferences thông thường không cung cấp bất kỳ bảo vệ mật mã nào: tệp XML có thể được đọc bởi bất kỳ tiến trình nào có quyền root hoặc qua adb backup. EncryptedSharedPreferences mã hóa dữ liệu ở cấp ứng dụng và khóa chính được lưu trữ trong Android Keystore với tùy chọn bảo vệ phần cứng (StrongBox).

Đặc điểmSharedPreferencesEncryptedSharedPreferences
Lưu trữXML thuần túyTệp nhị phân được mã hóa
Mã hóaKhôngAES-256 GCM + SIV
Bảo vệ khóaKhôngAndroid Keystore + StrongBox
Hiệu suất0.1-1 ms2-15 ms
Khuyến nghịCài đặt giao diệnToken, khóa, PII

Khi nào nên chọn EncryptedSharedPreferences

Sử dụng EncryptedSharedPreferences để lưu trữ: token làm mới OAuth, khóa API cho các dịch vụ bên ngoài, email hoặc số điện thoại của người dùng và cài đặt ứng dụng nhạy cảm (PIN, cờ xác thực). EncryptedSharedPreferences không phù hợp để lưu trữ dữ liệu sinh trắc học hoặc tài liệu lớn — thay vào đó, hãy sử dụng EncryptedFile hoặc Room với SQLCipher.

Nguyên tắc chung: nếu rò rỉ dữ liệu gây hại cho người dùng hoặc doanh nghiệp — hãy sử dụng EncryptedSharedPreferences. Nếu dữ liệu chỉ mang tính thẩm mỹ (chủ đề, ngôn ngữ, sắp xếp) — SharedPreferences thông thường. Việc triển khai EncryptedSharedPreferences ngay từ đầu là hợp lý, mà không cần tái cấu trúc: việc thay thế trong dự án hiện có sẽ yêu cầu di chuyển và xử lý dữ liệu cũ chưa được mã hóa.

Hãy nhớ rằng EncryptedSharedPreferences không bảo vệ dữ liệu trong khi ứng dụng đang chạy — chỉ trên đĩa. Nếu kẻ tấn công có quyền truy cập vào bộ nhớ tiến trình, dữ liệu đã giải mã có thể bị chặn. Sử dụng biện pháp bảo vệ bổ sung: ProGuard/DexGuard để làm rối mã.

Câu hỏi thường gặp

EncryptedSharedPreferences khác DataStore như thế nào?

Jetpack DataStore là một giải pháp thay thế hiện đại hơn cho SharedPreferences, dựa trên Flow và coroutine Kotlin. DataStore không mã hóa dữ liệu theo mặc định, nhưng có thể kết hợp với EncryptedSharedPreferences hoặc sử dụng mã hóa thủ công qua Proto DataStore với các giao thức mật mã.

Có thể sử dụng EncryptedSharedPreferences cho khối lượng dữ liệu lớn không?

Không được khuyến nghị. EncryptedSharedPreferences được thiết kế cho khối lượng nhỏ (lên đến 100-200 KB). Đối với dữ liệu lớn hơn, hãy sử dụng Room với SQLCipher hoặc mã hóa tệp qua EncryptedFile từ cùng thư viện AndroidX Security.

EncryptedSharedPreferences có hỗ trợ di chuyển khi cập nhật lược đồ không?

Không, không có di chuyển lược đồ tự động. Khi thay đổi cấu trúc dữ liệu, nhà phát triển phải đọc thủ công dữ liệu cũ qua KeyGen cũ và ghi chúng qua KeyGen mới. Nên lưu trữ phiên bản lược đồ trong một tham số riêng.

Cấp API tối thiểu yêu cầu là bao nhiêu?

AndroidX Security 1.0.0 hỗ trợ API 19+ (Android KitKat). Phiên bản 1.1.0-alpha06 cũng hỗ trợ API 19+. StrongBox yêu cầu API 28+ và thiết bị có hỗ trợ phần cứng (Google Pixel 3+, Samsung Galaxy S9+).

Có an toàn để lưu trữ refresh token trong EncryptedSharedPreferences không?

Có, refresh token là một trong những trường hợp sử dụng chính. Mã hóa AES-256 GCM, khóa chính trong Keystore, bảo vệ sinh trắc học — mức độ đủ cho token OAuth. Đối với token truy cập ngắn hạn cũng phù hợp, mặc dù một số nhóm thích lưu trữ chúng trong bộ nhớ.

Tóm tắt

  • EncryptedSharedPreferences — trình bao bọc SharedPreferences với mã hóa tự động qua AES-256 GCM (giá trị) và SIV (khóa)
  • Master Key được tạo qua MasterKey.Builder và lưu trữ trong Android Keystore với các tùy chọn sinh trắc học và StrongBox
  • API hoàn toàn tương thích: edit, putString, getString, apply, clear — tất cả như SharedPreferences thông thường
  • Hiệu suất: 2-15 ms mỗi thao tác, người dùng không nhận thấy trong các tình huống tiêu chuẩn
  • Bảo mật: mã hóa xác thực (AEAD) ngăn chặn cả việc đọc và giả mạo dữ liệu
  • Di chuyển từ SharedPreferences thông thường yêu cầu chuyển dữ liệu thủ công qua tệp cũ và mới
  • Sử dụng EncryptedSharedPreferences cho token, khóa API, mật khẩu và các cài đặt nhạy cảm khác

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm