How to securely store access token and secret in Android?
我将使用OAuth从Google获取邮件和联系人。我不想每次都要求用户登录以获取访问令牌和机密。根据我的理解,我需要将它们与我的应用程序存储在数据库或
将它们存储为共享首选项。默认情况下,它们是私有的,其他应用程序无法访问它们。在根设备上,如果用户明确地允许访问一些试图读取它们的应用程序,那么应用程序可能能够使用它们,但您无法对此进行保护。至于加密,您必须要求用户每次输入解密密码短语(从而破坏了缓存凭据的目的),或者将密钥保存到文件中,这样您就会遇到同样的问题。
存储令牌而不是实际的用户名密码有一些好处:
- 第三方应用程序不需要知道密码,用户可以确保只将其发送到原始站点(Facebook、Twitter、Gmail等)。
- 即使有人偷了一个令牌,也不能看到密码(用户可能也在其他站点上使用)。
- 令牌通常有一个生存期,并在一段时间后过期。
- 如果怀疑令牌已被泄露,则可以撤销令牌。
您可以将它们存储在AccountManager中。这些人认为这是最佳实践。
官方定义如下:
This class provides access to a centralized registry of the user's
online accounts. The user enters credentials (username and password)
once per account, granting applications access to online resources
with"one-click" approval.
有关如何使用AccountManager的详细指南:
- 乌迪科恩教程
- 皮兰特博客
- 谷歌IO演示
但是,在最后,AccountManager只将令牌存储为纯文本。所以,我建议在将您的秘密存储到accountmanager之前对其进行加密。您可以使用各种加密库,如aescrypt或aescrypt
另一种选择是使用隐藏库。它对Facebook足够安全,而且比AccountManager更容易使用。下面是使用hidden保存机密文件的代码段。
1 2 | byte[] cipherText = crypto.encrypt(plainText); byte[] plainText = crypto.decrypt(cipherText); |
sharedreferences本身不是安全位置。在根设备上,我们可以轻松地读取和修改所有应用程序的sharedreferencesxml,因此令牌应该相对频繁地过期。但是,即使令牌每小时过期一次,新的令牌仍然可以从共享的引用中被盗。Android密钥库应用于长期存储和检索加密密钥,这些密钥将用于加密我们的令牌,以便将它们存储在共享的引用或数据库中。密钥不存储在应用程序的进程中,因此很难被破坏。
因此,比一个地方更重要的是,它们如何能够自身安全,例如,使用加密签名的短命JWT,使用Android密钥库对它们进行加密,并使用安全协议发送它们。
现在将读取访问令牌和秘密加载到应用程序模块的build.gradle文件中。然后您需要为您的访问令牌和秘密定义buildconfig变量,这样您就可以直接从代码中访问它们。build.gradle可能如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ... ... ... android { compileSdkVersion 26 // Load values from keystore.properties file def keystorePropertiesFile = rootProject.file("keystore.properties") def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) defaultConfig { applicationId"com.yourdomain.appname" minSdkVersion 16 targetSdkVersion 26 versionCode 1 versionName"1.0" testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner" // Create BuildConfig variables buildConfigField"String","ACCESS_TOKEN", keystoreProperties["ACCESS_TOKEN"] buildConfigField"String","SECRET", keystoreProperties["SECRET"] } } |
您可以在代码中使用访问令牌和密码,如下所示:
1 2 | String accessToken = BuildConfig.ACCESS_TOKEN; String secret = BuildConfig.SECRET; |
这样,您就不需要将访问令牌和秘密以纯文本的形式存储在项目中。因此,即使有人解压缩您的APK,他们永远不会得到您的访问令牌和秘密,因为您正在从外部文件加载它们。
您可以通过以下两个选项来保护您的访问令牌。