如何在Android中安全存储访问令牌和秘密?

时间:2012-04-15 10:38:38

标签: android security oauth preferences token

我将使用oAuth从谷歌获取邮件和联系人。我不想每次都要求用户登录以获取访问令牌和密码。根据我的理解,我需要将它们与我的应用程序一起存储在数据库或SharedPreferences中。但我有点担心安全问题。我读过你可以加密和解密令牌,但攻击者很容易反编译你的apk和类并获得加密密钥。
在Android中安全存储这些令牌的最佳方法是什么?

5 个答案:

答案 0 :(得分:103)

将它们存储为共享首选项。这些默认为私有,其他应用无法访问它们。在有根设备上,如果用户明确允许访问某些尝试读取它们的应用程序,则该应用程序可能能够使用它们,但您无法防范这种情况。至于加密,您必须要求用户每次都输入解密密码(因此无法缓存凭据的目的),或者将密钥保存到文件中,您会遇到同样的问题。

存储令牌而不是实际的用户名密码有一些好处:

  • 第三方应用不需要知道密码,用户可以确定只将其发送到原始网站(Facebook,Twitter,Gmail等)。
  • 即使有人窃取了令牌,也无法看到密码(用户可能在其他网站上使用的密码)
  • 代币通常具有生命周期并在一定时间后过期
  • 如果您怀疑他们已被盗用,可以撤销令牌

答案 1 :(得分:15)

您可以将它们存储在AccountManager中。据这些人说,这被认为是最佳实践。

enter image description here

这是官方定义:

  

此类提供对用户的集中注册表的访问   在线帐户。用户输入凭据(用户名和密码)   每个帐户一次,授予应用程序访问在线资源的权限   “一键”批准。

有关如何使用AccountManager的详细指南:

但是,最后AccountManager只将您的令牌存储为纯文本。所以,我建议在将它们存储在AccountManager之前加密你的秘密。您可以使用各种加密库,例如AESCryptAESCrypto

另一种选择是使用Conceal library。它对Facebook来说足够安全,比AccountManager更容易使用。这是使用隐藏保存秘密文件的代码片段。

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);

答案 2 :(得分:6)

  1. 在Android Studio的“项目”窗格中,选择"项目文件"并创建一个名为" keystore.properties"的新文件。在项目的根目录中。
  2. enter image description here

    1. 打开" keystore.properties"文件并将您的访问令牌和密钥保存在文件中。
    2. enter image description here

      1. 现在,在 app 模块的 build.gradle 文件中加载读取访问令牌和密钥。然后,您需要为Access Token和Secret定义BuildConfig变量,以便您可以直接从代码中访问它们。您的 build.gradle 可能如下所示:

        ... ... ... 
        
        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"]
            }
        }
        
      2. 您可以在代码中使用Access Token and Secret,如下所示:

        String accessToken = BuildConfig.ACCESS_TOKEN;
        String secret = BuildConfig.SECRET;
        
      3. 这样您就不需要在项目中以纯文本形式存储Access Token和Secret。因此,即使有人反编译您的APK,当您从外部文件加载它们时,它们也永远不会获得您的访问令牌和秘密。

答案 3 :(得分:5)

SharedPreferences is not一个安全的位置。在root设备上,我们可以轻松读取和修改所有应用程序的SharedPrefereces xml。所以令牌应该过期相对频繁。但即使令牌每小时到期,仍然可以从SharedPreferences中窃取新的令牌。 Android KeyStore应该用于加密密钥的长期存储和检索,加密密钥将用于加密我们的令牌以便将它们存储在例如密钥中。 SharedPreferences或数据库。密钥不会存储在应用程序的进程中,因此它们会被are harder泄露。

因此,与地方相关的是它们本身如何安全,例如使用加密签名的短期JWT,使用Android KeyStore加密它们并使用安全协议发送它们

答案 4 :(得分:2)

您可以通过以下两个选项保护您访问令牌。

  1. 使用将您的访问令牌保存到不会反向的android密钥库中。
  2. 使用NDK函数进行一些计算,使用难以反转的c ++代码保存令牌和NDK