一、数据存储与加密:本地数据加密、密钥管理与最小化存储
说实话,Android 开发这么多年,我踩过最深的坑就是数据存储。你以为存在手机里就安全了?太天真了。SharedPreferences 明文存密码、SQLite 裸奔存用户信息,这些我都在项目里见过。今天咱们就聊聊怎么把本地数据真正锁起来。
1.1 本地数据加密:别让数据裸奔
先说说最常见的两个场景:键值对存储和数据库存储。Android 官方其实给了我们现成的方案,但很多人不知道,或者懒得用。
EncryptedSharedPreferences:官方推荐
SharedPreferences 默认是明文存储的。root 过的手机,随便一个文件管理器就能看到你的数据。我有个朋友,他们的 app 把用户 token 直接存 SP,结果被用户投诉隐私泄露……
用 EncryptedSharedPreferences 其实很简单:
// 初始化
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
// 存数据
sharedPreferences.edit().putString("user_token", "xxx").apply();
// 读数据
String token = sharedPreferences.getString("user_token", null);
你看,代码几乎没变,只是换了个类。但背后做了两件事:密钥加密和值加密。密钥用 AES256-SIV,值用 AES256-GCM。说白了,就算有人拿到文件,也解不开。
SQLCipher:给 SQLite 加把锁
如果你用 Room 或者原生 SQLite,数据也是明文的。SQLCipher 是 SQLite 的加密扩展,能对整个数据库文件加密。
集成方式:
// build.gradle
implementation 'net.zetetic:android-database-sqlcipher:4.5.6'
// 使用
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(
"data.db",
"your_password",
null
);
嗯,这里要注意:密码不能硬编码。我见过有人直接把密码写在代码里,那跟没加密有什么区别?密码应该从 Android Keystore 里取,或者用生物识别解锁。
1.2 密钥管理:Android Keystore 才是亲爹
加密的密钥放哪?这是个灵魂问题。你放文件里,别人能读;你放代码里,别人能反编译。Android Keystore 是硬件级别的安全存储,密钥一旦生成,就无法从设备中导出。
为什么这么牛?因为密钥存在 TEE(可信执行环境)里,app 进程根本拿不到密钥明文。你只能用它加密解密,但不能把它拷走。
使用示例:
// 生成密钥
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
);
keyGenerator.init(spec);
keyGenerator.generateKey();
// 加密
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey key = (SecretKey) keyStore.getKey("my_key", null);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedData = cipher.doFinal(plaintext.getBytes());
你想想看,密钥存在 Keystore 里,就算 app 被脱壳、被 hook,攻击者也拿不到密钥。这才是真正的安全感。
1.3 数据最小化存储策略:能不存就不存
加密再强,也不如不存。GDPR 和个人信息保护法都强调数据最小化原则。说白了,你只存业务必须的数据,其他的一律不碰。
我总结了几条实操建议:
- 能不存就不存:比如用户位置,用完就删,别留着做分析
- 能脱敏就脱敏:手机号存后四位,身份证只存哈希
- 能过期就过期:设置 TTL,到期自动清理
- 能本地就不上传:敏感数据尽量留在本地,别往服务器传
举个例子:你的 app 需要用户手机号做登录。你可以只存手机号的 SHA-256 哈希,用于校验。真正的手机号,用完就丢。这样就算数据库泄露,攻击者也拿不到原始手机号。
知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以看到,数据存储、加密、密钥管理、最小化策略,其实是环环相扣的。
你看,整个架构分四层:数据存储负责加密落地,密钥管理负责保护钥匙,加密算法提供技术保障,最小化策略从源头减少风险。四者缺一不可。
公众号:蓝海资料掘金营,微信deep3321