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

yea*_*man 114 security android oauth token preferences

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

Nik*_*kov 111

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

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

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

  • 这不再是现在存储代币的最佳方式! (4认同)
  • @RahulRastogi 最好的方法是什么? (3认同)
  • 您必须以(有点)混淆的方式将应用程序置于应用程序中,以便在反编译后它们不会立即可见,或者使用您自己的具有密钥和密钥的authrorization代理Web应用程序.将它们放入应用程序显然更容易,如果认为有人试图破解您的应用程序的风险足够低,请采取这种方法.顺便说一句,以上几点是针对用户密码的.如果您发现您的消费者密钥/秘密已被泄露,您也可以撤销它们(当然,这会破坏您的应用程序). (2认同)

ald*_*dok 17

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

在此输入图像描述

这是官方定义:

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

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

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

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

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
Run Code Online (Sandbox Code Playgroud)

  • 隐藏的好小费.看起来很容易使用.对于许多用例. (2认同)

ape*_*x39 8

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

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

  • 那我们可以在哪里存储它们呢? (4认同)
  • @MilindMevada 通过使用 [android 帐户管理器](https://developer.android.com/training/id-auth/identify) (手动加密,因为帐户管理器仅存储纯文本),或 [android 密钥库]( https://developer.android.com/training/articles/keystore) (2认同)

小智 6

正如此问题的最新更新一样,您现在可以使用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()
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记将导入添加到 build.gradle 实现 'androidx.security:security-crypto:1.0.0' (2认同)