Android SharedPreferences 加密存储解决方案

Android开发中,SharedPreferences接口提供了一种访问和修改基本数据类型键值对的通用框架。这些数据即使在应用程序被杀死后也能跨用户会话持久化存储。然而,默认情况下,这些数据以未加密的XML文件形式存储在设备的文件系统中,并且只有应用程序可以访问这个文件。这种存储方式虽然提供了一定程度的隐私保护,但并不完全安全。如果Android设备被root,具有root权限的其他应用就可以读取、下载或修改这个文件。即使设备没有被root,攻击者如果物理接触到设备,也可能通过Android Debug Bridge (ADB)等工具下载所有数据。因此,对数据进行加密变得尤为重要。

为什么需要加密SharedPreferences

SharedPreferences接口允许访问和修改基本数据类型的键值对(布尔值、数字、字符串等)。这些数据在用户会话之间持久化,即使应用程序被关闭。然而,如果Android设备被root,其他具有root权限的应用可以读取、下载或修改这个文件。更糟糕的是,即使设备没有被root,攻击者如果物理接触到设备,也可能通过ADB等工具下载所有数据。因此,对SharedPreferences中的数据进行加密,即使攻击者获取了数据,也无法读取或修改,从而保护了数据的安全

如何使用加密SharedPreferences

Android中,有三种方法可以初始化SharedPreferences对象:

SharedPreferences prefs = getSharedPreferences(String name, int mode); SharedPreferences prefs = getPreferences(int mode); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(Context context);

本文介绍的类接受一个Context对象,并在内部使用第三种方法。因此,应该使用以下方式初始化SharedPreferences对象:

SharedPreferences prefs = new SecurePreferences(this);

这个类目前没有接受现有SharedPreferences对象进行包装的构造函数。这是出于安全考虑,但未来版本的文档可能会提供额外的构造函数。此外,构造函数还会在内存中初始化加密/解密密钥。

SecurePreferences类的实现

SecurePreferences类实现了SharedPreferences接口,提供了与SharedPreferences对象相同的使用方式。不同之处在于,SecurePreferences类会透明地加密和解密提供的键和值。例如,获取和设置字符串的方式如下:

String value = prefs.getString("myKey", "defaultValue"); prefs.edit().putString("myKey", "myValue").commit();

这些调用的实现如下:

@Override public String getString(String key, String defaultValue) { final String encryptedValue = SecurePreferences.sFile.getString(SecurePreferences.encrypt(key), null); return (encryptedValue != null) ? SecurePreferences.decrypt(encryptedValue) : defaultValue; } @Override public SharedPreferences.Editor putString(String key, String value) { mEditor.putString(SecurePreferences.encrypt(key), SecurePreferences.encrypt(value)); return this; }

请注意,这个类要求API级别至少为8(Android2.2,即"Froyo")或更高。示例中展示了字符串的处理,但SharedPreferences接口的所有其他数据类型(布尔值、浮点数、整数、长整数和字符串集合)也都支持。

注意事项

"应用沙箱"概念提供了一定程度的默认隐私保护。了解这种默认行为的细节非常重要,以免无意中更改并削弱应用程序的安全性。SharedPreferences对象应该使用MODE_PRIVATE标志初始化,SharedPreferences对象的持久化XML文件应该存储在设备的内部存储中,而不是SD卡上,因为外部存储上没有强制执行权限。

进一步改进

如果敏感数据是用户凭据,建议不要将用户名和密码存储在设备上。相反,使用用户提供的用户名和密码进行初始认证,然后使用一个短期的、特定服务的授权令牌。对于一般敏感数据,可以选择使用一个密钥来加密本地文件,这个密钥不直接对应用程序可访问。例如,可以将密钥放在KeyStore中,并用一个不存储在设备上的用户密码保护。如果应用程序需要额外的加密,推荐的方法是需要一个密码或PIN来访问应用程序。这个密码可以输入到PBKDF2中生成加密密钥。换句话说,一个更安全的方法是一个秘密的PIN/密码/密码,这个密码根本不存储在设备上。要么用户提供它,要么一个远程且安全的服务器(这将需要互联网连接和更深入的安全评估)。这个秘密将被应用程序转换为加密/解密密钥。这样,即使设备落入错误之手,黑客数据的唯一方法就是暴力攻击。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485