我的自定义密码哈希算法不安全吗?

信息安全 密码 php
2021-09-03 06:24:57

对于我所有的爱好网络项目,我编写了一个这些项目共享的登录系统。这些项目中没有关键数据,唯一的关键数据是可以重复使用的密码。所以我尝试以一种非常安全的方式散列密码。

我目前的密码散列算法并不是我认为真正安全的。当我看到 PHP 现在提供内置散列时password_hash,我想到了切换。

我的问题是,转换对我有什么好处?就我而言,我可以获得哪些额外的保护,我要修复哪些漏洞等?为了不让它变得非常不安全,我还需要做些什么吗?

我想把这些答案作为自己的学习经验,这样我就可以把它教给在我这个职位上的其他人。

我当前的算法(伪代码):

Salt = "some-salt" 
Repeat 1000000 times
    Password = Sha512(Salt + username + Salt + Password) 

我知道我的网站容易受到定时攻击,PHP 内置函数可以解决这个问题。

还有什么明显不安全的?

4个回答

对于初学者,您推出了自己的密码散列算法。目前只有三种密码哈希算法被认为是安全的:

  • PBKDF2
  • 加密
  • bcrypt

您正在迭代并且正在添加盐。您似乎还在算法中添加了用户名,这并没有增加任何好处,因为您已经在使用盐。

我不能从您的代码中扣除什么,而这非常重要的是您的盐的长度以及您如何生成它。盐永远不应该被硬编码,而是在对密码进行散列时随机生成。salt 在数据库中应该是唯一的,最好是全局唯一的,以避免在不同的数据库中识别相似的密码(因此用户名不被认为是好的 salt)。

此外,PBKDF2 的工作方式(最接近您的实现)是使用 HMAC,其中随机生成的盐是用于计算消息摘要的密钥,而不是将所有内容附加在一起。PHP 的 password_hash 使用的是 bcrypt 算法。

因此,总结一下使用标准算法而不是您自己的算法获得的收益:

  • 您将生成随机盐
  • 您将使用标准化且安全的密码哈希算法

假设some-salt事实上从未重复,这是一种可接受的密码散列方法。它结合了三个基本要素:无法从密码中恢复散列(由于使用 SHA-512)、内在缓慢(由于大量 SHA-512 迭代)和唯一盐。

salt 必须是全局唯一的:它不能用于散列其他密码、在密码更改或其他人的密码数据库中散列相同的密码。违反唯一性并不是绝对关键,但它发生的越多,攻击者就越容易做到这一点。在范围的极端,“盐”是恒定的,它不是盐,而且您的密码散列方法很糟糕。如果是用户名或记录 id,仍然很糟糕,因为多个数据库将共享一小组盐。

尽管如此,您应该使用标准的散列方法。您的方法中可能存在我们遗漏的漏洞,因为它依赖于一些微妙的细节。您可能在实施中犯了错误;出于这个原因,带有安全更新的良好支持的实现是更可取的。算法中可能会发现一个弱点;同样,最好使用支持良好的实现,其实现者随时了解密码学新闻,并在必要时更改算法。

您需要注意的一件事是随着时间的推移和计算机变得更快,增加迭代次数。一个好的

阅读如何安全地散列密码?(是的,全部)。Bcrypt 在某种程度上优于 PBKDF2,因为它更能抵抗基于 GPU 的攻击;PBKDF2 遵循与您的自定义哈希相同的原则。目前使用 PBKDF2 并不是一个主要漏洞,但我仍然建议切换到 bcrypt 或 scrypt。

您的算法比许多“自制”算法要好几英里。我仍然会改用标准化标准的原因是,您可以从这些标准所接受的所有审查中受益,而您自己的构建却没有。

在你的构造中绝对没有允许微不足道的休息的错误吗?如果不是,您确定您的算法不会受到使用大规模并行 GPU 的加速蛮力攻击的影响吗?您的特定算法是否存在优化形式的彩虹表攻击?

答案可能是不,不,不,但是更多的人关注 PBKDF2,而不是你的算法,所以到目前为止没有人发现的讨厌的东西不太可能。这是一个启发式的论点,但不要忘记,即使你的算法很好(在我看来它肯定不愚蠢),还有数百人实现了他们自己的加密,结果却被严重破坏了. 这就是为什么我们通常说,不要自己动手。

这与我们不允许任何人安装和修改高压电气连接的原因相同:拥有电工资格并不能神奇地保护您免于触电,但这意味着您希望在该领域获得足够的经验而不做任何太愚蠢的事情,比如抓住一根随机电线,看看它是否有电。

将用户名作为 salt 的一部分包含的一个缺点是,它意味着您无法在不生成新密码哈希的情况下重命名用户(例如,以管理方式)(这意味着您必须选择一个新密码并告诉用户,或者询问用户为他们当前的密码)。