Android中SharedPreferences不安全本地存储防护方法咨询
默认的SharedPreferences会把数据以明文XML格式存在应用私有目录的/data/data/[应用包名]/shared_prefs/路径下,root设备、开启调试的设备、获得提权权限的恶意应用都可以直接读取文件内容,这也是渗透测试能轻易拿到存储值的核心原因。可以按以下层级做防护,从根源限制未授权访问:
1. 先划清存储边界
不要什么数据都往SharedPreferences里放:
- 高敏感数据(用户登录核心Token、支付密钥、密码、身份证/银行卡明文等)绝对不要存在SharedPreferences里,哪怕做了加密也不行,这类数据应该直接用系统Keystore做硬件级存储,不要落盘到SP的XML文件中
- 中低敏感数据(脱敏业务标识、短期缓存、用户偏好配置)可以存在加密后的SharedPreferences中
2. 用官方加密库实现加密存储,不要自己写伪加密
不要自己手写加密逻辑、硬编码密钥——大部分自实现的SP加密都是把AES密钥写在常量类或者BuildConfig里,反编译APK就能直接拿到密钥,和明文存储没有区别。直接用AndroidX官方的安全组件即可,密钥由系统AndroidKeyStore托管,不可被导出,就算拿到root权限也读不出密钥:
首先引入依赖:
dependencies { implementation "androidx.security:security-crypto:1.1.0-alpha06" }
初始化加密SP实例:
// 生成托管在AndroidKeyStore的256位AES主密钥,不支持导出 val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() // 获取加密SP实例,键用AES256-SIV加密,值用AES256-GCM加密 val encryptedSp = EncryptedSharedPreferences.create( context, "secure_prefs_file", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM )
后续读写操作和普通SharedPreferences的API完全一致,加解密逻辑自动完成,不需要额外处理。
注意:这个方案支持Android 6.0(API23)及以上系统,覆盖当前98%以上的活跃Android设备。
3. 做好基础访问配置,避免低级漏洞
- 创建SP实例时永远使用
MODE_PRIVATE模式,MODE_WORLD_READABLE、MODE_WORLD_WRITEABLE这两个允许其他应用读写SP的模式从Android7.0开始已经被系统直接禁止调用,老版本上使用会直接把SP数据暴露给所有安装的应用 - 不要把SP文件创建在外置存储目录,外置存储的文件默认对所有应用可读,没有任何访问限制
- Debug构建变体下不要写入生产环境的真实敏感数据,避免调试阶段泄露加密逻辑、测试数据
4. 低版本兼容与加固补充
如果需要兼容Android 5.0及以下的极低版本设备,可以补充以下防护:
- 密钥不要硬编码在APK中,可以结合设备硬件信息(比如ANDROID_ID、硬件序列号)+ 服务端下发的盐值派生加密密钥,避免逆向后直接拿到固定密钥
- 敏感值存储前加随机盐,不要直接加密原始值,避免通过密文特征、长度反向推断明文内容
- 开启R8/ProGuard混淆,把SP操作、密钥派生相关的类名、方法名、字段名全部混淆,增加静态逆向成本
- 核心密钥派生逻辑可以放到Native层实现,相比Java层代码,so库的逆向成本会高很多
没有任何方案可以做到100%防破解,安全防护的核心是提高攻击成本,让未授权获取数据的成本高于数据本身的价值。不要把SP作为敏感数据的唯一存储防线,最高敏感级别的数据优先用系统级的硬件安全模块存储。
内容的提问来源于stack exchange,提问作者I'm Coder
相关产品推荐
相关产品推荐

