我将使用oAuth从谷歌获取邮件和联系人 . 我不想每次都要求用户登录以获取访问令牌和密码 . 根据我的理解,我需要将它们与我的应用程序一起存储在数据库或 SharedPreferences 中 . 但我有点担心安全问题 . 我读过你可以加密和解密令牌,但是攻击者很容易反编译你的apk和类并获得加密密钥 .What's the best method to securely store these tokens in Android?
SharedPreferences
将它们存储为共享首选项 . 这些默认为私有,其他应用无法访问它们 . 在root设备上,如果用户明确允许访问某些尝试读取它们的应用程序,则该应用程序可能能够使用它们,但您无法防范这种情况 . 至于加密,您必须要求用户每次都输入解密密码(因此无法缓存凭据的目的),或者将密钥保存到文件中,您会遇到同样的问题 .
存储令牌而不是实际的用户名密码有几个好处:
第三方应用程序不需要知道密码,用户可以确定它们只将其发送到原始站点(Facebook,Twitter,Gmail等)
即使有人窃取了令牌,也无法看到密码(用户可能在其他网站上使用的密码)
代币通常具有生命周期并在一定时间后过期
如果您怀疑它们已被盗用,则可以撤销令牌
您可以将它们存储在AccountManager中 . 根据这些人的说法,它被认为是最佳实践 .
这是官方定义:
此类提供对用户在线帐户的集中注册表的访问 . 用户每个帐户输入一次凭据(用户名和密码),通过“一键”批准授予应用程序访问在线资源的权限 .
有关如何使用AccountManager的详细指南:
Udi Cohen tutorial
Pilanites blog
Google IO presentation
但是,最后AccountManager仅将您的令牌存储为纯文本 . 所以,我建议在将它们存储在AccountManager之前加密你的秘密 . 您可以使用各种加密库,如AESCrypt或AESCrypto
另一种选择是使用Conceal library . 它's safe enough for Facebook and much easier to use than AccountManager. Here'是一个使用Conceal保存秘密文件的代码片段 .
byte[] cipherText = crypto.encrypt(plainText); byte[] plainText = crypto.decrypt(cipherText);
... ... ... 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"] } }
String accessToken = BuildConfig.ACCESS_TOKEN; String secret = BuildConfig.SECRET;
这样,您就不需要在项目中以纯文本形式存储Access Token和Secret . 因此,即使有人反编译您的APK,当您从外部文件加载它们时,它们也永远不会获得您的访问令牌和秘密 .
SharedPreferences is not一个安全的位置 . 在root设备上,我们easily可以读取和修改所有应用程序' SharedPrefereces xml' s . 即使令牌每小时到期,仍然可以从SharedPreferences中窃取新的令牌 . Android KeyStore应该用于加密密钥的长期存储和检索,加密密钥将用于加密我们的令牌以便将它们存储在例如密钥中 . SharedPreferences . 密钥不存储在应用程序的进程中,因此它们会受到损害 .
您可以通过以下两个选项保护您访问令牌 .
使用将访问令牌保存到不会反向的android密钥库中 .
使用NDK函数进行一些计算,使用非常难以反转的c代码保存令牌和NDK
5 回答
将它们存储为共享首选项 . 这些默认为私有,其他应用无法访问它们 . 在root设备上,如果用户明确允许访问某些尝试读取它们的应用程序,则该应用程序可能能够使用它们,但您无法防范这种情况 . 至于加密,您必须要求用户每次都输入解密密码(因此无法缓存凭据的目的),或者将密钥保存到文件中,您会遇到同样的问题 .
存储令牌而不是实际的用户名密码有几个好处:
第三方应用程序不需要知道密码,用户可以确定它们只将其发送到原始站点(Facebook,Twitter,Gmail等)
即使有人窃取了令牌,也无法看到密码(用户可能在其他网站上使用的密码)
代币通常具有生命周期并在一定时间后过期
如果您怀疑它们已被盗用,则可以撤销令牌
您可以将它们存储在AccountManager中 . 根据这些人的说法,它被认为是最佳实践 .
这是官方定义:
有关如何使用AccountManager的详细指南:
Udi Cohen tutorial
Pilanites blog
Google IO presentation
但是,最后AccountManager仅将您的令牌存储为纯文本 . 所以,我建议在将它们存储在AccountManager之前加密你的秘密 . 您可以使用各种加密库,如AESCrypt或AESCrypto
另一种选择是使用Conceal library . 它's safe enough for Facebook and much easier to use than AccountManager. Here'是一个使用Conceal保存秘密文件的代码片段 .
这样,您就不需要在项目中以纯文本形式存储Access Token和Secret . 因此,即使有人反编译您的APK,当您从外部文件加载它们时,它们也永远不会获得您的访问令牌和秘密 .
SharedPreferences is not一个安全的位置 . 在root设备上,我们easily可以读取和修改所有应用程序' SharedPrefereces xml' s . 即使令牌每小时到期,仍然可以从SharedPreferences中窃取新的令牌 . Android KeyStore应该用于加密密钥的长期存储和检索,加密密钥将用于加密我们的令牌以便将它们存储在例如密钥中 . SharedPreferences . 密钥不存储在应用程序的进程中,因此它们会受到损害 .
您可以通过以下两个选项保护您访问令牌 .
使用将访问令牌保存到不会反向的android密钥库中 .
使用NDK函数进行一些计算,使用非常难以反转的c代码保存令牌和NDK