Android(Java)运行时存储敏感数据的安全性及合规方案咨询
Android(Java)敏感数据存储与传递的安全性问题
嘿,这个问题问到点子上了——把密码这类敏感数据存在普通Java变量里,还通过Intent在Activity之间传递,绝对是不安全的,具体风险和正确方案我给你理清楚:
为什么普通变量+Intent传递不安全?
- 内存泄露风险:普通变量里的明文密码会留在应用的堆内存中,就算你把变量置为
null,垃圾回收(GC)也不会立刻覆盖这块内存的内容。要是设备被root,或者有恶意应用通过内存dump工具读取,分分钟就能拿到明文密码。而且String类型更危险,因为它是不可变的,会在字符串常量池里留存更久,很难彻底清除。 - Intent传递的暴露风险:用Intent的
putExtra传密码时,这些数据会被系统写入日志(比如你用logcat就能看到),要是应用有漏洞,第三方还能通过拦截进程间通信拿到这些数据。
正确的实现方式
1. 内存中安全存储敏感数据
- 用Android Keystore加密存储:这是Android官方推荐的安全方案。你可以通过Keystore生成一个对称密钥,用这个密钥把密码加密成字节数组存在内存里,密钥本身会被系统存在硬件安全模块(支持的设备)或者系统级安全存储中,你的应用进程拿不到明文密钥。就算内存被dump,拿到的也是加密后的内容,没有密钥根本解不开。
- 用
char[]代替String:char[]是可变的,当你不需要密码时,可以用Arrays.fill(charArray, '0')把数组内容覆盖成无效值,能更快清除内存里的敏感数据,而String做不到这一点。 - 封装安全的单例管理类:写一个单例类专门管理敏感数据,内部用加密后的字节数组或者
char[]存储,只提供安全的获取方法,并且在用户退出时主动清理数据。比如:
import java.util.Arrays; public class SecureDataManager { private static SecureDataManager instance; private char[] encryptedPassword; // 或者存储Keystore加密后的字节数组 private SecureDataManager() {} public static synchronized SecureDataManager getInstance() { if (instance == null) { instance = new SecureDataManager(); } return instance; } public void setEncryptedPassword(char[] password) { this.encryptedPassword = password.clone(); } public char[] getEncryptedPassword() { return encryptedPassword != null ? encryptedPassword.clone() : null; } public void clearData() { if (encryptedPassword != null) { Arrays.fill(encryptedPassword, '0'); encryptedPassword = null; } } }
2. Activity间安全传递敏感数据
- 尽量避免直接传递:不要把密码放到Intent里,让目标Activity直接从上面的
SecureDataManager单例中获取加密后的或者临时解密的数据。 - 万不得已要传递时:先通过Keystore加密密码,传递加密后的字节数组,目标Activity拿到后再解密,用完立刻把解密后的明文清除(比如用
Arrays.fill覆盖char[])。
3. 应用退出时的清理
- 在用户退出应用的入口(比如点击退出按钮、应用被销毁前),主动调用
SecureDataManager.getInstance().clearData(),彻底清除内存中的敏感数据,减少泄露风险。
额外注意点
- 绝对不要把明文密码写入任何持久化存储(比如SharedPreferences、SQLite),如果必须持久化,一定要用Keystore加密后再存储。
- 对于root设备,安全风险会大幅提升,你可以在应用启动时检测设备是否root,必要时限制敏感功能的使用。
内容的提问来源于stack exchange,提问作者J K
相关产品推荐
相关产品推荐

