Web应用程序 - 存储密码

时间:2011-06-24 07:21:46

标签: passwords security hash salt

我错过了什么吗?是否有任何其他步骤将密码存储到数据库中?

存储密码:
经过尽可能多的研究,我得出的结论是,在Web应用程序数据库(在我的例子中是MySQL + PHP)中存储用户密码的最佳方法如下:

  • 指定全站点静态盐。 (16兰特字符包括0-9,a-z,A-Z,[] / * - ')
  • 为每个用户分配一个随机盐(存储在数据库中)。
  • 存储结果hash_function($ userPassword + $ sitewideSalt + $ randomSalt)
  • 将$ randomSalt存储在生成的哈希旁边。
  • 使用bcrypt可调工作负载 散列

  • 攻击#1: 攻击者通过SQL注入转储数据库。
    DB结果 我们的hash_function和随机的每个 用户盐。

    攻击后,攻击者可以 获取 $ userPassword 和 通过查找自己的帐户 $ randomSalt 。然后通过猜测哈希 像md5这样的功能他可以开始了 彩虹袭击了 的 $ sitewideSalt 即可。但这可能需要1.41亿 几个世纪以来[1]。

    通过使用此类安全性 不允许转储数据库来破坏存​​储的密码 。用户仍需通过其他方法找到 $ sitewideSalt

  • 攻击#2: 攻击者找到本地文件包含(LFI)向量。
    攻击者可以获取我们的Web应用程序的原始代码。

          通过可能的LFI利用Web应用程序之后 或RFI [2]攻击者读取 我们网站的源代码 申请并获得我们的简单 算法和存储的 的 $ sitewideSalt


下一步?
现在,攻击者拥有他可以开始彩虹的两种盐来获取实际的密码。除非他必须为每个用户制作1个彩虹表,因为每个用户都有不同的随机用户特定盐($ randomSalt)。

  

“现代服务器可以计算MD5   每秒大约330MB的哈希值。如果   您的用户拥有密码   小写,字母数字和6   人物长,你可以尝试每一个   单个可能的密码   在大约40秒内。“
”...... CUDA,你可以将自己的小型超级计算机集群放在一起,让你每秒可以尝试大约700,000,000个密码......“[3]

我们现在需要做的是使用耗时的算法扩展散列函数,例如bcrypt。 bcrypt的工作负载因子可以是更简单的散列函数的5-6个数量级。破解一个密码可能需要数年而不是几分钟。并且作为奖励,bcrypt已经为每个哈希生成随机盐并将其存储在结果哈希中。

  1. http://www.grc.com/haystack.htm
  2. http://www.wildcardsecurity.com/security101/index.php?title=Local_File_Inclusion

2 个答案:

答案 0 :(得分:3)

干得好!看起来非常完整。

我只有建议:

旋转服务盐。

设计一种方法,定期旋转服务范围的盐,并定期锻炼。

例如,在生成新的服务盐之后,将其用于所有新帐户&任何密码更改。当现有用户尝试登录时,使用旧服务盐对其进行身份验证。如果成功,则使用新服务盐(以及可选的新用户特定盐)更新其哈希值。对于未“登录”某段时间的用户,请代表他们随机生成新密码。这将为那些放弃您网站的用户“保持”安全性,迫使那些返回使用密码重置设施的用户。 ('某个时候'=你不熟悉的任何时期)。

不要对服务盐进行硬编码。

不要让LFI攻击危及您的服务盐。在启动时将service-salt提供给应用程序,并将其保存在内存中。为了破坏服务盐,攻击者需要能够执行代码以从内存中读取salt。如果攻击者能够做到这一点,那么无论如何你都会受到很好的冲击。 =)

不要重复使用用户盐。

寻找为用户提供新盐的机会。用户更改密码?生成一个新的随机盐。如果攻击者能够在他感觉到的时候能够获得他的哈希值,这进一步阻碍了暴力强制你的服务器范围的盐。结合这个经常旋转你的服务盐,我打赌你已经有强大的威慑力来反抗暴力。

(如果其他人有其他想法,请将此标记为社区维基)。

答案 1 :(得分:1)

使用BCrypt处理密码是唯一的步骤,或者更确切地说,包含以下内容:

  1. 获取密码,将其提供给BCrypt库。
  2. 存储结果哈希。
  3. 将密码与哈希进行比较。
  4. 您也忘了这个链接:http://codahale.com/how-to-safely-store-a-password/这是您引用的引用。