如何在 Android 上安全地存储密码?

Posted

技术标签:

【中文标题】如何在 Android 上安全地存储密码?【英文标题】:How to safely store passwords on Android? 【发布时间】:2015-03-24 02:17:45 【问题描述】:

任务是保存输入的密码(PasswordStr)或mKey.getEncoded byte[],稍后自动发送到Crypto API(Cipher)

    SecretKey mKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(PasswordStr.toCharArray());

很明显,这个密码也可以加密,但这需要另一个密码,以此类推到无穷大。

可能 android 已经提供了存储密码的机制?

p.s 使用远程服务器是不可能的。需要本地存储。

【问题讨论】:

您的用例是什么?为什么您需要存储密码或密钥?目前尚不清楚您是否要存储密码或密钥。如果可以选择,请保存生成的 key (当然还有公共盐)。您不想将用户密码泄露给其他方! 最好存储字符串密码。但原则上考虑到 Java 代码的脆弱性,这并不重要。我想确保我的用户数据的安全性。反编译后可以看到加盐、迭代等。 现在它更没有意义了。盐不应该在代码中,盐应该是随机的,而不是this kind of random。盐和迭代计数可以是公开的。 也许我对密码学的了解不多。但是,公共盐有什么意义呢?还是使用盐只会增加密码破解时间?如果是这样,存储密码而不是 SecretKey 更有意义 盐用于确保无法创建彩虹表并确保您无法发现两个人(或不同情况下的同一个人)重复使用密码,导致相同密码哈希。因此,它可以毫无问题地公开。有时会用一种称为胡椒的静态/秘密盐来扩展它,但仍然需要盐。不要存储密码;人们可能会重复使用密码,因此如果密码以某种方式泄露,您将承担损失。 【参考方案1】:

您可以将SQLCipher 用于安卓系统。它是SQLite 的扩展,提供透明的 256 位 AES 数据库文件加密

【讨论】:

如果没有更多的安全细节,这个答案并不像它可能的那么强大。 AES-256 实际上并没有说明所提供的安全级别。【参考方案2】:

检查Handling Credentials section on the android developers guide。我会在这里引用它。

在可能的情况下,用户名和密码不应存储在设备上。相反,使用用户提供的用户名和密码执行初始身份验证,然后使用短期、服务特定的授权令牌

应使用AccountManager 访问多个应用程序可以访问的服务。如果可能,请使用 AccountManager 类调用基于云的服务,并且不要在设备上存储密码。

在使用AccountManager 检索Account 之后,CREATOR 在传递任何凭据之前,这样您就不会无意中将凭据传递给错误的应用程序。

如果凭据仅由您创建的应用程序使用,那么您可以使用checkSignature() 验证访问 AccountManager 的应用程序。或者,如果只有一个应用程序将使用该凭据,您可以使用 KeyStore 进行存储。

【讨论】:

这都是正确的,但有时存在存储密码的有效用例(即用于 3rd 方服务),而这个答案没有解决这些问题。【参考方案3】:

你可以使用安卓的Keystore API

秘密由从手机密码或 pin 派生的主密码加密。它被认为是一个很好的基于软件的加密解决方案。请注意,用户必须在手机上设置密码/pin 才能使用。

Nelenkov gives a good overview:

Android 的凭据存储是作为原生 Linux 服务实现的 (守护进程),在它上面有一些额外的层使它可用 到框架。让我们快速回顾一下我们对密钥库的了解 守护进程(这里有更详细的描述):

它是一个本地守护进程,在启动时启动 它提供了一个本地控制套接字以允许应用程序和系统服务与之对话 它使用 AES 128 位主机加密密钥 密钥加密的密钥存储在 /data/misc/keystore 中,每个密钥一个文件 主密钥源自设备解锁密码或 PIN 码 根据调用者 UID 授权管理命令执行和密钥访问

有关详细信息,请参阅Android Documentation。

【讨论】:

我对此表示反对,因为我认为这不会解决问题。问题是安全地存储密码,而不是密钥。使用平台密钥库一般来说是个好主意,但需要补充一个关于如何使用它存储密码的示例。 在您的示例中,您指的是密钥,所以我认为这对您来说是一个可行的解决方案。您当然可以使用密钥来加密密码(或其他任何内容),这将使您摆脱密码循环(“......但这将需要另一个密码,依此类推直到无穷大。”) 好吧,我以为这是要求的,但现在我感到困惑。撤销投票,询问组织。 cmets 中用于澄清的海报。 现在改为赞成。您应该存储派生的密钥或秘密,而不是密码(如果需要存储任何内容)。但是,这确实意味着您还必须将盐存放在某个地方。 "主密钥是从设备解锁密码或PIN中派生出来的" 如果用户没有在系统上设置PIN怎么办? KeyStore 不起作用?不知怎的,这并不好

以上是关于如何在 Android 上安全地存储密码?的主要内容,如果未能解决你的问题,请参考以下文章

如何在移动设备上安全地存储数据?

安全地存储密码,但确定相同的密码

如何在移动应用程序中安全地存储密码

如何安全地存储 .pfx 密码以在 MSBuild 中使用?

程序员必备基础:如何安全传输存储用户密码?

如何安全地存储用户的密码?