EncryptedSharedPreferences:是什么、API及如何使用

作者: IT Sectr 发布日期: 2026-03-14 阅读时间: 10 分钟

EncryptedSharedPreferences — 是AndroidX Security库的组件,提供通过SharedPreferences API保存数据的透明加密。与普通SharedPreferences(数据存储在开放的XML文件中)不同,EncryptedSharedPreferences在写入磁盘前自动加密键和值。根据Android Developers,该库对值使用AES-256 GCM,对键使用AES-256 SIV(RFC 5297),确保数据的机密性和完整性。

要点

  • EncryptedSharedPreferences — 围绕SharedPreferences的包装器,自动加密所有保存的数据
  • 加密通过Android Keystore对值使用AES-256 GCM,对键使用AES-256 SIV
  • 认证加密(AEAD)保证数据在写入后未被修改
  • 主密钥存储在Android Keystore中,在具有TEE的设备上受硬件保护
  • API完全兼容SharedPreferences — 替换无需更改读写代码

什么是EncryptedSharedPreferences?

EncryptedSharedPreferences — 是来自androidx.security.crypto包的类,在AndroidX Security 1.0.0(2019)中引入。它实现了SharedPreferences接口,但所有写操作(putString、putInt、putBoolean等)预先加密数据,读操作在返回前解密数据。

普通SharedPreferences的问题

标准SharedPreferences将数据保存在应用程序目录中的XML文件中(/data/data/package/shared_prefs/)。文件未加密 — 通过root权限访问设备或分析备份时,所有数据都可以作为普通XML读取。身份验证令牌、API密钥、用户的个人数据对攻击者来说都是可访问的。

EncryptedSharedPreferences在库级别解决了这个问题:数据在写入磁盘前加密,读取时解密。开发人员无需手动调用加密函数 — API与普通SharedPreferences保持一致。

历史与版本

AndroidX Security库 v1.0.0 于2019年12月发布。EncryptedSharedPreferences取代了通过Cipher + SharedPreferences进行手动加密的过时方法。当前稳定版本是1.1.0-alpha06(2024),支持API 19+。该库是Jetpack的一部分,不需要额外的权限。

根据Google Security Blog(2024),EncryptedSharedPreferences是存储不需要通过云同步的敏感应用程序设置的推荐方法。对于更复杂的场景,建议使用带有SQLCipher加密的Room。

EncryptedSharedPreferences如何工作?

EncryptedSharedPreferences使用两级加密方案:主密钥(Master Key)存储在Android Keystore中,数据加密使用派生密钥。这是Keystore保护和对称加密性能的结合。

加密方案:AES-256 GCM + SIV

对于,使用AES-256 GCM(Galois/Counter模式)— 认证加密模式(AEAD),确保数据的机密性和完整性。对于(参数名称),应用AES-256 SIV(RFC 5297)— 确定性加密,用于在不泄露内容的情况下按键搜索。

每个文件EncryptedSharedPreferences包含加密的键值对。文件结构:首先是带有元数据的头部(版本、密钥标识符),然后是加密条目列表。该文件不是有效的XML,无法在文本编辑器中读取。

MasterKey和KeyStore

MasterKey类负责创建和管理存储在Android Keystore中的256位主密钥。MasterKey.Builder允许配置:存储类型(Keystore或软件)、生物识别保护、密钥生命周期。默认情况下,主密钥在Android Keystore中使用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
    )
}

加密配置

EncryptedSharedPreferences.create接受五个参数:上下文、文件名、主密钥、密钥加密方案和值加密方案。方案的选择影响性能和保护级别。

密钥加密方案

AES256_SIV — 确定性加密:相同的键始终产生相同的密文。这对于按键搜索(SharedPreferences.getX(key))是必需的。缺点:攻击者可以通过重复的密文确定使用了哪些键。AES256_SIV2 — 带有额外随机化的改进版本。

对于,使用AES256_GCM。GCM为每个值添加12字节的IV(初始化向量)和16字节的身份验证标签。这确保了机密性(没有人可以读取值)和认证(没有人可以在不被检测到的情况下修改值)。

主密钥的生物识别保护

MasterKey.Builder中的setUserAuthenticationRequired(true)方法要求从Keystore获取主密钥前进行生物识别确认。这增加了一个额外的层面:即使应用程序在已解锁的设备上运行,攻击者也无法在没有Face ID或Touch ID的情况下读取EncryptedSharedPreferences。

重要:使用setUserAuthenticationRequired时,如果用户更改或删除生物识别信息,主密钥将变得不可用。需要处理KeyPermanentlyInvalidatedException并创建一个新的主密钥并进行数据迁移。

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) {
        // 生物识别已更改 — 需要重新创建密钥
    }
}

Kotlin使用示例

让我们看一个在Kotlin Android应用程序中集成EncryptedSharedPreferences的完整示例。库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)的工作方式相同。区别仅在内部:数据在写入时加密,在读取时解密。

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

从普通SharedPreferences迁移

要将现有数据从不受保护的SharedPreferences迁移到EncryptedSharedPreferences,需要:从旧文件中读取所有数据,创建新的EncryptedSharedPreferences,写入所有数据,删除旧文件。Google不提供内置的迁移工具 — 开发人员自行实现。

与普通SharedPreferences的比较

SharedPreferences和EncryptedSharedPreferences之间的选择取决于存储数据的类型。对于界面设置(主题、语言、排序),普通SharedPreferences就足够了。对于敏感信息(令牌、密码、密钥),EncryptedSharedPreferences是必需的。

性能

EncryptedSharedPreferences由于加密操作比普通版本慢。写入一个字符串值大约需要5-15毫秒(取决于数据大小和硬件AES加速)。读取 — 2-5毫秒。对于大多数应用程序来说,这是不可察觉的,但在批处理操作(迁移、恢复)中,最好使用apply()而不是commit()。

安全性

普通SharedPreferences不提供任何加密保护:XML文件可以被任何具有root权限的进程或通过adb backup读取。EncryptedSharedPreferences在应用程序级别加密数据,主密钥存储在Android Keystore中,具有硬件保护(StrongBox)的可能性。

特性SharedPreferencesEncryptedSharedPreferences
存储开放XML加密的二进制文件
加密AES-256 GCM + SIV
密钥保护Android Keystore + StrongBox
性能0.1-1毫秒2-15毫秒
推荐UI设置令牌、密钥、PII

何时选择EncryptedSharedPreferences

使用EncryptedSharedPreferences存储:OAuth刷新令牌、外部服务的API密钥、用户的电子邮件或电话号码、敏感的应用程序设置(PIN、身份验证标志)。对于存储生物识别数据或大型文档,EncryptedSharedPreferences不适合 — 使用EncryptedFile或带有SQLCipher的Room。

通用规则:如果数据泄露会损害用户或业务 — 使用EncryptedSharedPreferences。如果数据仅是装饰性的(主题、语言、排序) — 普通SharedPreferences。立即实施EncryptedSharedPreferences是合理的,无需重构:在现有项目中替换需要迁移和处理旧的未加密数据。

请记住,EncryptedSharedPreferences仅在磁盘上保护数据 — 不在应用程序运行时。如果攻击者可以访问进程内存,解密的数据可能会被截获。使用额外的保护:ProGuard/DexGuard进行代码混淆。

常见问题

EncryptedSharedPreferences与DataStore有何区别?

Jetpack DataStore — 是SharedPreferences的更现代替代方案,基于Flow和Kotlin协程。DataStore默认不加密数据,但可以与EncryptedSharedPreferences组合使用,或通过Proto DataStore使用加密协议进行手动加密。

EncryptedSharedPreferences可以用于大量数据吗?

不推荐。EncryptedSharedPreferences设计用于小体积数据(最多100-200 KB)。对于大数据,使用带有SQLCipher的Room或通过来自同一AndroidX Security库的EncryptedFile进行文件加密。

EncryptedSharedPreferences在模式更新时支持迁移吗?

不,没有自动模式迁移。在更改数据结构时,开发人员必须通过旧的KeyGen手动读取旧数据并通过新的KeyGen写入。建议在单独的参数中存储模式版本。

所需的最低API级别是多少?

AndroidX Security 1.0.0支持API 19+(Android KitKat)。版本1.1.0-alpha06也支持API 19+。对于StrongBox,需要API 28+和具有硬件支持的设备(Google Pixel 3+、Samsung Galaxy S9+)。

在EncryptedSharedPreferences中存储刷新令牌安全吗?

是的,刷新令牌是主要使用场景之一。AES-256 GCM加密、Keystore中的主密钥、生物识别保护 — 对OAuth令牌来说足够。对于生命周期短的访问令牌也适用,尽管有些团队更喜欢将其存储在内存中。

总结

  • EncryptedSharedPreferences — SharedPreferences包装器,通过AES-256 GCM(值)和SIV(键)自动加密
  • 主密钥通过MasterKey.Builder创建,存储在Android Keystore中,具有生物识别和StrongBox选项
  • API完全兼容:edit、putString、getString、apply、clear — 全部与普通SharedPreferences相同
  • 性能:每次操作2-15毫秒,在标准场景中对用户不可察觉
  • 安全性:认证加密(AEAD)防止读取和修改数据
  • 迁移从普通SharedPreferences需要通过旧文件和新文件手动传输数据
  • 将EncryptedSharedPreferences用于令牌、API密钥、密码和其他敏感设置

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读