我打算使用oAuth从谷歌获取邮件和联系人。我不想每次要求用户登录以获取访问令牌和密钥。据我所了解,我需要使用数据库或SharedPreferences
将它们存储在我的应用程序中。但是我有一些安全方面的担忧。我读到可以加密和解密这些标记,但攻击者很容易反编译您的apk和类并获取加密密钥。
在Android上安全地存储这些令牌的最佳方法是什么?
我打算使用oAuth从谷歌获取邮件和联系人。我不想每次要求用户登录以获取访问令牌和密钥。据我所了解,我需要使用数据库或SharedPreferences
将它们存储在我的应用程序中。但是我有一些安全方面的担忧。我读到可以加密和解密这些标记,但攻击者很容易反编译您的apk和类并获取加密密钥。
在Android上安全地存储这些令牌的最佳方法是什么?
将它们存储为共享偏好。这些默认是私有的,其他应用程序无法访问它们。在已root的设备上,如果用户明确允许某个试图读取它们的应用程序访问它们,那么该应用程序可能能够使用它们,但您无法防范这种情况。至于加密,您必须要求用户每次输入解密密码(从而破坏了缓存凭据的目的),或者将密钥保存到文件中,这样会出现同样的问题。
与实际的用户名密码相比,存储令牌有以下几个好处:
以下是官方定义:
该类提供对用户在线帐户的集中式注册表的访问。 用户仅一次输入凭据(用户名和密码),即可授权应用程序通过“单击”批准访问在线资源。
有关如何使用 AccountManager 的详细指南:
但是,最终 AccountManager 只会将您的令牌以纯文本形式存储。因此,我建议在将其存储在 AccountManager 之前对您的秘密进行加密。您可以利用各种加密库,例如 AESCrypt 或 AESCrypto
另一个选择是使用 Conceal library。它对 Facebook 来说足够安全,并且比 AccountManager 更容易使用。这是使用 Conceal 保存秘密文件的代码段。
byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
SharedPreferences不是一个安全的位置。在已经取得root权限的设备上,我们可以轻松地读取和修改所有应用程序的SharedPrefereces的xml文件。因此令牌应该相对频繁地过期。但即使令牌每小时过期一次,最新的令牌仍然可能会从SharedPreferences被窃取。Android KeyStore 应该用于长期存储和检索加密密钥,这些密钥将用于加密我们的令牌以便存储到例如 SharedPreferences 或数据库中。密钥未存储在应用程序的进程内,因此更难被破解。
因此,比位置更相关的是它们本身如何保持安全,例如使用加密签名的短期JWT,在 Android KeyStore 中使用加密,并使用安全协议发送它们。
针对此问题,有一个最新的更新,你现在可以使用EncryptedSharedPreferences来安全地存储数据。 接口非常相似,但你还需要生成一个 MasterKey。
大多数 EncryptedSharedPreferences 的文档使用 MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC,但这已被弃用,可以使用MasterKey.Builder代替。
private var masterKeyAlias = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
private val preferences = EncryptedSharedPreferences.create(
context,
"auth_token_secured",
masterKeyAlias,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
var authToken: String?
get() = preferences.getString("auth_token", "")
set(value) = preferences.edit().putString("auth_token", value).apply()
Auth0 提供了一个实用类来存储令牌。最好使用该实用库。有两个类可用于管理凭据: