存储密码:
经过尽可能多的研究,我得出的结论是,在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).
“A modern server can calculate the MD5
hash of about 330MB every second. If
your users have passwords which are
lowercase,alphanumeric,and 6
characters long,you can try every
single possible password of that size
in around 40 seconds.”
“…CUDA,you can put together your own little supercomputer cluster which will let you try around 700,000,000 passwords a second…”[3]
我们现在需要做的是使用耗时的算法扩展散列函数,例如bcrypt. bcrypt的工作负载系数可以是简单哈希函数的5-6个数量级.破解一个密码可能需要数年而不是几分钟.并且作为奖励,bcrypt已经为每个哈希生成随机盐并将其存储在结果哈希中.
> http://www.grc.com/haystack.htm
> http://www.wildcardsecurity.com/security101/index.php?title=Local_File_Inclusion
解决方法
我只有建议:
旋转服务盐.
设计一种定期旋转服务范围的盐并定期锻炼的方法.
例如,在生成新的服务盐之后,将其用于所有新帐户&任何密码更改.当现有用户尝试登录时,使用旧服务盐对其进行身份验证.如果成功,则使用新服务盐(以及可选的新用户特定盐)更新其哈希值.对于未“登录”某段时间的用户,请代表他们随机生成新密码.这将为那些放弃您网站的用户“保持”安全性,迫使那些返回使用密码重置设施的用户. (‘一段时间’=你不熟悉的任何时期).
不要硬编码服务盐.
不要让LFI攻击危及您的服务盐.在启动时将service-salt提供给应用程序,并将其保存在内存中.为了破坏服务盐,攻击者需要能够执行代码以从内存中读取salt.如果攻击者能够做到这一点,那么无论如何你都会受到很好的冲击. =)
不要重复使用用户盐.
寻找机会为用户提供新盐.用户更改了密码?生成一个新的随机盐.如果攻击者能够在他感觉到的时候能够获得他的哈希,这进一步阻碍了暴力强制你的服务器范围的盐.结合这个经常旋转你的服务盐,我打赌你已经有强大的威慑力来打击暴力.
(如果其他人有其他想法,请将此标记为社区维基).