我错过了什么吗?是否有其他步骤将密码存储到数据库?
存储密码:
nbsp nbsp;在对这个主题进行了尽可能多的研究后,我得出结论,在web应用程序数据库(在我的例子中是MySQL+PHP)中存储用户密码的最佳方式如下:
- 指定站点范围的静态salt。(16个兰特字符,包括0-9、a-z、a-z、[]/*-')
- 为每个用户分配一个随机salt(存储在DB中)
- 存储结果hash_function($userPassword+$sitewideSalt+$randomSalt)
- 将$randomSalt与生成的哈希一起存储
- 使用bcrypt可调整的工作负载散列
-
攻击#1: 攻击者通过SQL注入转储数据库
nbsp nbsp;的数据库结果我们的hash_function和随机per用户盐转储后,攻击者可以获取$userPassword,并$randomSalt通过查找自己的帐户。然后通过猜测散列像md5这样的功能他可以启动彩虹攻击$站点范围盐。但这可能需要141亿美元几个世纪[1]。
通过使用这种类型的安全性不允许转储数据库以破坏存储的密码。用户仍然需要通过另一种方法找到$sitewideSalt
-
攻击#2: 攻击者找到本地文件包含(LFI)向量
nbsp nbsp;攻击者可以获取我们的web应用程序的原始代码
在通过可能的LFI开发web应用程序之后或RFI[2],攻击者读取我们网站的源代码应用程序并获得我们的简单算法和存储的
$站点范围盐。
下一步在哪里
nbsp nbsp;现在攻击者拥有了这两种盐,他可以开始彩虹般地获得实际密码。但他必须为每个用户制作一个彩虹表,因为每个用户都有不同的随机用户特定盐($randomSalt)。
"现代服务器可以计算MD5每秒大约330MB的哈希。如果您的用户的密码是小写、字母数字和6字符长,您可以尝试该大小的单个可能密码在大约40秒内。"
"。。。CUDA,你可以组建自己的小型超级计算机集群,让你每秒尝试大约70000000个密码。。。"[3]
nbsp nbsp;我们现在需要做的是通过使用诸如bcrypt之类的耗时算法来扩展哈希函数。bcrypt的工作负载因子可以是简单散列函数的5-6个数量级。只破解一个密码可能需要几年而不是几分钟。另外,bcrypt已经为每个哈希生成了一个随机salt,并将其存储在生成的哈希中。
- http://www.grc.com/haystack.htm
- http://www.wildcardsecurity.com/security101/index.php?title=Local_File_Inclusion
干得好!在我看来非常完整。
我唯一的建议是:
旋转服务盐
设计一种方法来定期轮换服务范围内的盐,并定期进行锻炼。
例如,在生成新的服务salt之后,将其用于所有新帐户&任何密码更改。当现有用户尝试登录时,请使用旧的服务salt对其进行身份验证。如果成功,请使用新的服务salt(以及可选的新的用户特定salt)更新他们的散列。对于"一段时间"未登录的用户,请代表他们随机生成一个新密码。这将为放弃您的网站的用户"保持"安全,迫使那些返回的用户使用密码重置功能。("一段时间"=你觉得舒服的时间)。
不要硬编码您的服务盐
不要让LFI攻击损害您的服务盐。在启动时向应用程序添加服务盐,并将其保存在内存中。为了破坏服务salt,攻击者需要能够执行代码从内存中读取salt。如果攻击者能做到这一点,那么你已经被彻底击败了
不要重复使用用户的盐
寻找机会为用户提供新的盐类。用户更改密码?生成一个新的随机盐。如果攻击者能够随时获得他的哈希值,这将进一步阻碍对服务器范围内的salt进行暴力强制。再加上定期轮换你的服务salt,我敢打赌你对暴力强制有很强的威慑力。
(如果其他人有其他想法,请将其标记为社区wiki)。
使用BCrypt处理密码是唯一的步骤,或者更确切地说,包括以下步骤:
- 获取密码,将其提供给BCrypt库
- 存储生成的哈希
- 将密码与哈希进行比较
您还忘记了此链接:http://codahale.com/how-to-safely-store-a-password/这就是你引用的内容。