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


123

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


1
如何存储使用者密钥和机密(对它们进行严格加密并不安全)?我需要他们请求访问令牌和密码。.使用oauth的其他现有应用程序如何做到这一点?嗯,终于有了oauth,您需要为我解决更多的安全问题....我需要安全地保护消费者令牌/秘密以及accesstoken和秘密....最终,这不会更简单只需将用户的用户名/密码存储为加密?...最后,后者会更好吗?我只是仍然看不到oauth更好...
yeahman 2012年

你能告诉我..哪个文件存储访问令牌?我是Android的新手,我尝试运行示例Plus app。但我在[GoogleAuthUtil.getToken()方法中都找不到它。]
Abhishek Kaushik

Answers:


118

将它们存储为共享首选项。默认情况下,这些是私有的,其他应用无法访问它们。在具有root用户权限的设备上,如果用户明确允许访问尝试读取它们的某些应用程序,则该应用程序可能能够使用它们,但是您不能对此加以防范。至于加密,您要么要求用户每次都输入解密密码(从而破坏了缓存凭据的目的),要么将密钥保存到文件中,您会遇到相同的问题。

存储令牌代替实际的用户名密码有一些好处:

  • 第三方应用程序不需要知道密码,用户可以确保仅将其发送到原始网站(Facebook,Twitter,Gmail等)。
  • 即使有人窃取令牌,他们也看不到密码(用户也可能在其他站点上使用该密码)
  • 令牌通常具有生存期,并在一定时间后过期
  • 如果您怀疑令牌已被盗用,可以将其撤消

1
谢谢!但是我怎么知道我的用户密钥是否已被泄露?大声笑这将很难告诉..关于存储访问令牌和秘密,好吧,我将它们保存在sharedpreferences中并对其进行加密,但是消费者密钥和秘密呢?我不能将它们存储在sharedpreferences中(我首先需要在代码中显式地编写使用者密钥和秘密,以将其首先保存在sharedpreference中)..不知道您是否理解我的意思。
耶曼

2
您必须以某种混淆的方式将它们放入应用程序中,以使它们在反编译后不会立即可见,或者使用您自己的具有密钥和机密的身份验证代理网络应用程序。将它们放入应用程序显然更容易,并且如果认为有人试图破解您的应用程序的风险足够低,请采用这种方法。顺便说一句,以上几点是用户密码。如果您发现您的使用者密钥/秘密已被盗用,您也可以撤销它们(当然,这会破坏您的应用程序)。
Nikolay Elenkov 2012年

1
@NikolayElenkov:您写道:“对于加密,您要么必须要求用户每次都输入解密密码(这样就无法达到缓存凭据的目的),要么将密钥保存到文件中,您会遇到相同的问题。” 。如果破解者反转您的应用程序以了解加密的工作原理怎么办?您的防御可能会被破坏。使用本机代码存储此类信息(令牌,加密...)是最佳实践吗?
anhldbk 2014年

1
如果清除了应用程序数据,则刷新令牌将丢失,这可能不是用户想要的。
rds 2015年

1
这不是如今存储令牌的最佳方法!
拉胡尔·拉斯托吉

19

您可以将它们存储在AccountManager中。这些家伙认为这是最佳做法。

在此处输入图片说明

这是官方定义:

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

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

但是,最终AccountManager仅将您的令牌存储为纯文本。因此,我建议您先将您的机密加密,然后再将其存储在AccountManager中。您可以利用各种加密库,例如AESCrypt AESCrypto

另一种选择是使用隐蔽库。对于Facebook来说,它足够安全,并且比AccountManager更易于使用。这是使用Conceal保存机密文件的代码段。

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

2
隐藏的好提示。看起来非常好用。对于许多用例。
lagos

通过链接找不到隐藏。可能已停用
user1114

9

SharedPreferences 本身不是一个安全的位置。在有根设备上,我们可以轻松读取和修改所有应用程序的SharedPrefereces xml。因此令牌应该相对频繁地过期。但是,即使令牌每小时过期一次,仍可以从SharedPreferences中窃取更新的令牌。Android KeyStore应该用于长期存储和检索加密密钥,这些密钥将用于加密我们的令牌,以便将其存储在例如SharedPreferences或数据库中。密钥没有存储在应用程序的进程中,因此很难被盗用。

因此,与地方相比,更重要的是如何使它们本身安全,例如,使用经过加密签名的短命JWT,使用Android KeyStore对其进行加密并使用安全协议进行发送


9
那我们可以在哪里存储它们呢?
Milind Mevada

3
  1. 在Android Studio的“项目”窗格中,选择“项目文件”,然后在项目的根目录中创建一个名为“ keystore.properties”的新文件。

在此处输入图片说明

  1. 打开“ keystore.properties”文件,并将您的访问令牌和密钥保存在该文件中。

在此处输入图片说明

  1. 现在,将读取的访问令牌和密钥加载到应用程序模块的build.gradle文件中。然后,需要为访问令牌和密钥定义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. 您可以在代码中使用访问令牌和秘密,如下所示:

    String accessToken = BuildConfig.ACCESS_TOKEN;
    String secret = BuildConfig.SECRET;

这样,您就不需要在项目内以纯文本格式存储访问令牌和密钥。因此,即使有人反编译您的APK,当您从外部文件加载它们时,他们也永远不会获得您的访问令牌和秘密。


1
看起来创建属性文件而不是硬编码没有区别。
Dzshean '18年

我想在运行时写令牌,可能是我每次打开应用程序时都更改了令牌。
Rehan Sarwar '18

1
这是存储某些令牌(例如API访问令牌)的一种很好的方法。如果要存储用户凭据,NDK是更好的方法。
艾瑞克(Eric)

6
绝对不是您应该在应用程序中存储敏感信息的方式!即使存储库不使用此方法将数据包含在数据中(将数据注入到构建过程中),它也会生成一个BuildConfig文件,该文件具有纯文本的标记/秘密,供所有人查看,只需简单的反编译即可查看。
哈芬

-1

那么,您可以通过以下两种方法来确保访问令牌的安全。

  1. 使用将您的访问令牌保存到android keystore中,这不会反向。
  2. 使用NDK函数进行某些计算来保存令牌,并使用难以逆转的c ++代码保存NDK
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.