移动应用中的安全存储:定义、方法及实现

作者: IT Sectr 发布日期: 2026-04-04 阅读时间: 9 分钟

Secure Storage(安全存储)——一套保护设备上机密数据的方法和技术:令牌、加密密钥、支付信息及用户的个人数据。根据 OWASP Mobile Top 10(2024),不安全的数据存储位列三大最严重风险之中。正确实施安全存储即使在设备被物理访问时也能防止数据泄露。

要点

  • Secure Storage(安全存储)——一套在设备上加密和隔离数据的方法,以防止其他应用和攻击者的访问。
  • Android Keystore——在硬件级别(TEE)生成和保护密钥的加密存储库。
  • iOS Keychain——受保护的数据库,用于存储机密,在操作系统级别加密,通过 Security framework 访问。
  • EncryptedSharedPreferences——Android Jetpack 库,使用 AES-256 加密键值对。
  • Data Protection API——iOS 机制,根据与设备锁定状态相关的保护类加密文件。

什么是 Secure Storage?

Secure Storage(安全存储)——以其他应用、恶意软件以及具有设备物理访问权限的攻击者无法访问的方式存储移动应用机密数据的实践。与普通存储不同,Secure Storage 使用加密、隔离和硬件保护。

并非所有数据都需要 Secure Storage:个人资料图片或新闻缓存可以存储在普通文件系统中。但加密密钥、身份验证令牌、支付数据、私钥和生物识别模板必须受到保护。根据Google Security Blog(2025),移动应用中 67% 的漏洞与以开放形式存储机密有关。

每个移动平台都提供自己的 Secure Storage 机制:Android 提供 Keystore 和 EncryptedSharedPreferences,iOS 提供 Keychain 和 Data Protection API。这些机制与硬件安全模块(TEE、Secure Enclave)集成,确保即使在设备被越狱或 root 后也无法读取数据。

正确选择 Secure Storage 方法取决于数据类型、使用场景和性能要求。理解每种机制的架构使开发人员能够做出正确的架构决策。

Android 上的 Secure Storage

Android 平台提供多个数据保护级别,从硬件密钥存储到加密的 SharedPreferences。选择取决于数据的敏感性和性能要求。

Android Keystore —— 硬件密钥存储

Android Keystore —— 在支持硬件保护的设备上,在隔离执行环境(TEE —— Trusted Execution Environment)中生成和存储密钥的加密提供程序。密钥永远不会离开 TEE:加密操作在受保护区域内执行,该区域即使对操作系统也不可访问。

从 Android 9(API 28)开始,Keystore 支持 StrongBox Keymaster —— 一个专用的安全芯片,拥有自己的 CPU、真随机数生成器(TRNG)和保护内存。StrongBox 已通过 Common Criteria EAL 4+ 认证,是 Android 上最安全的密钥存储级别。要使用 StrongBox,需要在生成密钥时显式指定 inStrongBox() 标志。

Keystore 支持以下算法:AES/GCM/NoPadding(256 位)、EC(secp256r1、secp384r1)、RSA(2048–4096 位)和 HMAC-SHA256。所有密钥都可以通过 setUserAuthenticationRequired(true) 绑定到生物识别身份验证。

EncryptedSharedPreferences

EncryptedSharedPreferences —— 来自 AndroidX Security 包的库,自动加密通过 SharedPreferences API 存储的所有数据。值使用 AES-256 GCM 密钥加密,密钥使用 AES-256 SIV(合成 IV)加密,防止对密钥名称进行字典攻击。

主加密密钥存储在Android Keystore中,提供两级保护:Keystore 保护主密钥,EncryptedSharedPreferences 保护数据。对于典型数据(令牌、设置),加密性能每次读/写操作低于 5 毫秒,使该库适用于用户场景。

EncryptedSharedPreferences 不适用于大量数据(超过 5 MB)—— 在这种情况下,请使用通过 SQLCipher 或 Room 加密的数据库。

SQLCipher —— 加密数据库

SQLCipher —— SQLite 扩展,使用 AES-256-CBC 逐页加密整个数据库。数据库的每一页都使用通过 PBKDF2 从主密码派生的单独密钥加密。SQLCipher 根据数据大小增加约 5–15% 的性能开销。

与 Android 的集成通过 net.zetetic:android-database-sqlcipher 库实现,该库提供与标准 SQLiteOpenHelper 兼容的 API。建议将 SQLCipher 的密码存储在 Keystore 中,而不是代码或 SharedPreferences 中。

iOS 上的 Secure Storage

iOS 平台提供 Keychain Services —— 主要的安全存储,以及用于在操作系统级别加密文件的 Data Protection API。

Keychain Services

Keychain —— 一个加密的 SQLite 数据库,iOS 在其中存储密码、加密密钥、证书和笔记。每个 Keychain 元素(SecItem)都使用设备唯一的硬件密钥以加密形式存储。对元素的访问通过 ACL(访问控制列表)控制,可能需要生物识别身份验证(Face ID、Touch ID)或密码。

Keychain 支持保护类(Protection Class),确定数据何时可用:kSecAttrAccessibleWhenUnlockedThisDeviceOnly —— 数据仅在设备解锁时可用,并且在备份时不会传输。此类推荐用于大多数身份验证令牌存储场景。

在 iOS 15+ 上,Security framework 通过 Secure Enclave 提供硬件密钥支持 —— 一个专用的 Apple 处理器,处理加密操作并将私钥存储在隔离内存中。Secure Enclave 支持 ECDSA(secp256r1)和 ECDH 算法,生成无法从芯片中提取的密钥。

Data Protection API

Data Protection —— iOS 机制,使用与设备密码关联的密钥在文件系统级别(APFS)加密每个文件。开发人员在创建文件时通过 NSFileProtectionType 属性指定保护级别:NSFileProtectionComplete —— 文件仅在设备解锁时可用。

Data Protection 在所有 iOS 5+ 设备上自动运行(如果设置了密码)。加密通过 Apple 处理器的专用 AES 引擎在硬件级别执行,确保高性能 —— 加密延迟对用户几乎不可察觉。要在应用中激活保护,只需在通过 FileManager 创建文件时设置保护属性即可。

Data Protection 不能替代 Keychain 存储密钥 —— 它用于加密文件、Core Data 数据库和其他大量数据。Keychain(用于密钥)和 Data Protection(用于文件)的组合提供了 iOS 上完整的安全存储周期。

代码示例:在 Android 和 iOS 上加密数据

让我们看看使用 Android 和 iOS 内置 API 的Secure Storage实践示例。

Kotlin 中的 EncryptedSharedPreferences

示例展示了使用 Android Keystore 中的主密钥初始化 EncryptedSharedPreferences。所有后续的读写操作都会自动加密和解密。

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

Swift 中的 Keychain

示例演示了使用 Security framework 从iOS Keychain保存和读取数据。代码使用 kSecAttrAccessibleWhenUnlockedThisDeviceOnly 实现最大保护。

swift
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
}

Kotlin 中的 SQLCipher

通过SQLCipher连接到加密的 SQLite 数据库的示例,密码存储在 Android Keystore 中。

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

// 用法:打开时输入密码
val helper = SecureDBHelper(context)
val db = helper.getWritableDatabase(password)

安全数据存储建议

正确使用Secure Storage需要遵循几个基本原则,以防止开发人员的常见错误。

确定数据分类:哪些数据需要硬件保护(Keystore / Secure Enclave),哪些需要操作系统级别加密(EncryptedSharedPreferences / Data Protection),哪些可以存储在普通文件系统中。身份验证令牌、私钥和支付数据 —— 仅硬件级别。用户设置(主题、语言) —— EncryptedSharedPreferences 足够。会话数据(临时缓存)可以存储在内存或临时目录中。

切勿在代码中存储机密:包含 API 密钥、密码或种子短语的字符串在源代码中 —— 最严重的安全错误。任何逆向工程都会立即暴露这些数据。对密钥使用 Keystore,对配置使用应用启动时的服务器加载(remote config)。

对关键操作使用生物识别绑定:Android Keystore 和iOS Keychain支持将密钥绑定到生物识别身份验证。每次访问密钥时,系统都会要求 Face ID、Touch ID 或 Android 生物识别(BiometricPrompt)。这保证了即使在设备被完全控制的情况下,攻击者也无法在没有所有者的情况下使用存储的数据。

测试保护:使用安全分析工具 —— 静态分析使用 MobSF(Mobile Security Framework),运行时测试使用 objection,绕过保护使用 Frida。检查数据在 root 或越狱后是否不可访问。Android允许通过 SafetyNet Attestation 或 Play Integrity API 检查 root 访问的存在,iOS —— 通过验证 Secure Enclave 的完整性。

定期更新加密库:加密库中的漏洞会定期发现。跟踪 AndroidX Security、SQLCipher 和 Keychain 包装器的 CVE。通过 Dependabot 或 Renovate 实施新版本的自动通知系统。

根据Apple Security Research(2025),正确实施 Secure Storage 可防止 96% 针对从设备窃取数据的攻击。其余 4% —— 具有物理访问权限的零日漏洞利用攻击,生物识别绑定对其有效。

常见问题

Keychain 和 Keystore 有什么区别?

iOS Keychain —— 用于存储密码、密钥和证书的加密数据库,通过 ACL 进行访问控制。Android Keystore —— 在隔离环境(TEE/StrongBox)中生成和存储密钥的加密提供程序,不允许提取私钥。

EncryptedSharedPreferences 使用什么加密算法?

EncryptedSharedPreferences使用 AES-256 GCM 加密值,使用 AES-256 SIV 加密密钥。主密钥存储在 Android Keystore 中,提供两级保护。此外,还使用 HMAC-SHA256 进行完整性检查。

是否需要加密已受 HTTPS 保护的数据?

是的,HTTPS仅在传输通道中保护数据。在设备上,数据在解密后以开放形式存储。如果攻击者获得设备的物理访问权限或安装恶意软件,HTTPS 将无法保护存储的数据。始终在存储级别加密数据。

如何在 Android root 后保护数据?

使用带有 setUnlockedDeviceRequired(true) 标志的 Android Keystore,该标志阻止在 root 设备上访问密钥。此外,通过 Play Integrity API 检查完整性,如果偏离参考值,则清除存储中的所有机密。

可以在 iOS 上使用 UserDefaults 存储令牌吗?

不可以,UserDefaults以开放形式将数据存储在沙箱内的 plist 文件中。任何具有逆向工程工具(通过备份或越狱)的应用都可以读取令牌。只有 Keychain —— iOS 上唯一安全的机密存储位置。

总结

  • Secure Storage —— 移动应用的强制性保护组件,在物理访问设备时防止数据泄露。
  • 带 StrongBox 的 Android Keystore 在专用安全芯片上提供硬件密钥存储。
  • 带保护类(WhenUnlockedThisDeviceOnly)的 iOS Keychain —— Apple 平台上的机密存储标准。
  • EncryptedSharedPreferences —— Android 上用于加密设置和令牌的现成解决方案,具有两级加密。
  • SQLCipher —— 加密数据库的选择,具有逐页 AES-256-CBC 加密。
  • iOS 上的 Data Protection 和 Android 上的 SafetyNet/Play Integrity —— 文件系统的额外保护级别。
  • 根据 Apple Security Research 的数据,正确的数据分类和生物识别绑定可防止 96% 针对存储数据的攻击。

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

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

讨论项目

另请阅读