[ 译文原文:Where is the best place to store a password in your Android app ]
通常Android安全问题分为几个主要类别。首先,个人信息在电话上不安全地存储,其次,与任何后台数据库或Web服务器的不安全的通信。虽然还有很多其他的事情可能出错,但大多数安全问题都属于这两个方面。在这篇文章中,我们将介绍一些应用程序中保护个人信息的各种选项。
最好的选择是永远不要在手机上存储用户的个人信息,如密码或信用卡号码。如果让用户每次都输入密码不满足您的需求,那么您将不得不在设备上的某个地方存储用户名和密码。然而在Android设备上真的没有很多地方可以存储信息。通常来说都是将information存储在shared preferences
中,或在sqlite database中
或设备的密钥库(keystore)中存储。
在过去几年中,我经历了手动审核几百个Android应用程序的过程,在那段时间里,我看到了一些同样的安全问题,来来回回都是。尽管我们尽最大努力让开发者了解其应用程序的安全性问题,但是似乎在攻击应用程序方面,我们取得的成功更多,而不是让任何人可以拥有解决这些问题的办法。所以为了传播知识,让我们来看看一些真实世界中,开发人员试图隐藏密码信息的认证模式。
通过破解的难易顺序有一下排行:
- 存储在明文
- 使用对称密钥存储加密
- 使用AndroidKeystore
- 使用非对称密钥存储加密
明文
使用明文意味着对用户的运行时数据没有保护 - 假设黑客具有对手机的物理访问,这是一个很大的假设。但是,您必须假设您的应用程序迟早会在二手设备上结束。您可以访问应用程序的数据文件夹中的所有信息:
命令
adb backup
然后使用Android Backup Extractor或abe.jar将其转换为tar格式。例如:
adb backup com.packagename.android
java -jar abe.jar unpack backup.ab
tar -xvf backup.tar
大量应用程序使用的一个更好的选择是在AndroidManifest.xml中将android:allowBackup
标志设置为false
,然后将数据保存到shared preferences
或者sqlite database
。这个idea的想法是,如果没有人可以备份,那么没有人能够访问存储的密码。不幸的是,这个想法有很大的缺陷。如果手机在经过二手转售时没有被正确擦除,就可以root手机,并且通过更改File的权限,然后使用adb pull
命令来恢复App用户的任何动态数据(比如用户名和密码),即使不能使用adb backup
命令。以下是使用公开密码的shared preferences
file示例:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="password">2secret4me</string>
<boolean name="remember" value="true" />
<string name="username">androidauthority</string>
</map>
对称加密
比较明文存储的方式,一个更好的主意是在您保存密码之前加密密码。如果您要采取这种方法,那么不要将密钥存储在APK代码或手机中的其他任何地方。使用AES,DES或任何其他对称加密算法,如果将密钥存储在可以轻松找到的地方,这就相当于形同虚设。因为找到APK是一个比较简单的过程,接下来我们获取其备份副本。
在手机上获取APK的列表
adb shell pm list packages
找到APK在手机上的位置
adb shell pm path com.packagename.android
然后使用以下命令获取APK的副本
adb pull /data/app/com.packagename.android-1/base.apk
在适当的情况下对包名称和路径或apk名称进行适当的更改。
jadx base.apk
最后将代码反编译回java源代码,看看是否可以在代码中找到加密密钥。
如果您熟悉dex2jar,那么我建议切换到jadx。反编译比dex2jar好一个数量级。我以前用dex2jar审核过的许多应用程序,后来换了使用jadx后,他们丢失了他们的secrets。
在查找密钥的时候,我们可以利用开发人员的一些习惯,他们经常把加密密钥放在很容易找到像com.packagename.android.util.security
这样的地方。如果没有代码没有模糊化,而且您可以尝试搜索“加密”或“解密”等类名称或短语。想要要解密密码,将解密代码剪切并粘贴到java文件中,并将密码作为参数。
还有一些开发人员通过将包括AndroidID等设备信息以及制作和建模信息来使加密密钥具体化,但是如果您已经可以看到密钥在代码中的组合方式,这几乎是没有价值的。
AndroidKeystore
用于加密密码的最安全的选择是使用非对称加密算法,例如RSA。不对称意味着密钥分为公钥和私钥,只有私钥可以解密信息。我们看到更多的开发人员使用AndroidKeystore来存储公共和私人非对称密钥信息。
在AndroidKeystore中,这种公钥 - 私钥交换发生在设备上,似乎符合HIPAA标准。我们使用“似乎”这个词,是因为如果手机被root之后,您可以访问私钥。所以,没有什么是100%的安全,迟早有人会找到一种方法来获得钥匙,特别是如果你把所有东西放在同一个地方。
Android Keystore公钥和私钥都存储在:/data/misc/keystore/user_0
目录,私钥存储在具有<app_id>_USRCERT_<key_alias>
的文件中。在有根手机上,您可以将文件复制到另一个<app_id_malicious>_USRCERT_<key_alias>
,然后从你的恶意应用程序导入,您就可以恢复被加密过的密码数据。
[非译文] - 貌似Android现在可以提供硬件支持级别的密钥存储,这保证了即使系统或根应用程序也无法提取获得密钥。而针对物理访问攻击的保护是基于TrustZone实现的,低级别RSA算法的key store用于管理密钥是可行的,这使得应用程序可以使用Android内置的JCE,来提供应用程序未提供的加密算法。
[非译文] - 然而根据Android文档:Android Keystore System,key material 可以绑定到Android设备的安全硬件(例如,可信赖执行环境(TEE),安全元素(SE)),一些文章将这称之为硬件支持存储
,这意味着并不是所有的Android设备都支持这一点,如果设备不支持安全硬件,则将其存储在内部存储器中,某些文章称为软件备份存储
。对于在软件备份存储中提取密钥是否可行,没有具体的实践,以至于不清楚其是否安全。还是记住那句话,nothing is 100% safe。
非对称加密
更安全的非对称加密选项是远程存储私钥。首次输入密码时,将其发送到服务器进行存储,同时也使用公钥加密并存储在shared preferences
中。每当需要检查密码时,公钥加密的密码将被发送到后端服务器,并由私钥解密。然后检查服务器数据库中的密码信息。然后将令牌传递给Android客户端以允许访问该应用程序。手机上没有密码可见。