PHP 密码的安全哈希和盐

2022-08-30 05:44:39

目前据说MD5部分不安全。考虑到这一点,我想知道使用哪种机制进行密码保护。

这个问题,“双重散列”密码是否比仅仅散列一次更安全?表明多次散列可能是一个好主意,而如何为单个文件实施密码保护?建议使用盐。

我正在使用 PHP。我想要一个安全快速的密码加密系统。对密码进行一百万次哈希处理可能更安全,但也更慢。如何在速度和安全性之间取得良好的平衡?另外,我希望结果具有恒定数量的字符。

  1. 哈希机制必须在 PHP 中可用
  2. 它必须是安全的
  3. 它可以使用盐(在这种情况下,所有的盐都同样好吗?有没有办法产生好的盐?

另外,我是否应该在数据库中存储两个字段(例如,一个使用 MD5,另一个使用 SHA)?它会让它更安全还是更不安全?

如果我不够清楚,我想知道要使用哪些哈希函数以及如何选择一个好的盐,以便拥有安全快速的密码保护机制。

不太涵盖我的问题的相关问题:

PHP
简单密码加密
中的 SHA 和 MD5 有什么区别存储密钥、密码 asp.net
如何在 Tomcat 5.5 中实现加盐密码


答案 1

免责声明:这个答案写于2008年。

从那时起,PHP为我们提供了password_hashpassword_verify,并且自引入以来,它们是推荐的密码哈希和检查方法。

不过,答案的理论仍然是一个很好的阅读。

TL;DR

注意 事项

  • 不要限制用户可以输入的密码字符。只有白痴才会这样做。
  • 不要限制密码的长度。如果你的用户想要一个带有supercalifragilisticexpialidocious的句子,不要阻止他们使用它。
  • 不要在密码中去除或转义 HTML 和特殊字符。
  • 切勿以纯文本形式存储用户的密码。
  • 切勿通过电子邮件向用户发送密码,除非他们丢失了密码,并且您发送了临时密码。
  • 永远不要以任何方式记录密码。
  • 切勿使用SHA1或MD5甚至SHA256散列密码!现代饼干可以分别超过600亿和1800亿哈希/秒。
  • 不要将bcrypt与hash()的原始输出混合,要么使用十六进制输出,要么base64_encode它。(这适用于任何可能包含流氓的输入,这可能会严重削弱安全性。\0

剂量

  • 尽可能使用地下室;bcrypt 如果你不能。
  • 如果不能将 bcrypt 或 scrypt 与 SHA2 哈希一起使用,请使用 PBKDF2。
  • 在数据库遭到破坏时重置每个人的密码。
  • 实现合理的 8-10 个字符的最小长度,并需要至少 1 个大写字母、1 个小写字母、一个数字和一个符号。这将改善密码的熵,从而使其更难破解。(有关一些辩论,请参阅“什么才是好密码?”部分。

为什么要散列密码?

散列密码背后的目标很简单:通过破坏数据库来防止对用户帐户的恶意访问。因此,密码散列的目标是通过花费他们太多的时间或金钱来计算纯文本密码来阻止黑客或破解者。时间/成本是你武器库中最好的威慑力量。

您希望在用户帐户上获得良好,强大的哈希值的另一个原因是让您有足够的时间来更改系统中的所有密码。如果您的数据库遭到入侵,您将需要足够的时间至少锁定系统,如果不更改数据库中的每个密码。

Whitehat Security的首席技术官Jeremiah Grossman在最近的密码恢复后在White Hat Security博客上表示,该恢复需要暴力破解他的密码保护:

有趣的是,在度过这个噩梦的过程中,我学到了很多关于密码破解,存储和复杂性的知识。我开始理解为什么密码存储比密码复杂性更重要。如果您不知道密码是如何存储的,那么您真正可以依赖的就是复杂性。这可能是密码和加密专业人士的常识,但对于普通的InfoSec或Web安全专家来说,我非常怀疑这一点。

(强调我的。

究竟是什么造就了一个好密码?

。(并不是说我完全赞同兰德尔的观点。

简而言之,熵是密码内的变化程度。当密码只有小写罗马字母时,只有26个字符。这并没有太大的变化。字母数字密码更好,为36个字符。但允许大写和小写以及符号大约为96个字符。这比字母要好得多。一个问题是,为了使我们的密码令人难忘,我们插入了模式 - 这减少了熵。哎呀!

密码熵很容易近似。使用全部 ascii 字符(大约 96 个可键入字符)会产生每个字符 6.6 的熵,对于未来的安全性,8 个字符的密码仍然太低(52.679 位熵)。但好消息是:更长的密码和带有Unicode字符的密码确实增加了密码的熵,使其更难破解。

Crypto StackExchange网站上有一个关于密码熵的更长的讨论。一个好的谷歌搜索也会发现很多结果。

在我与@popnoodles交谈的评论中,他指出,使用X多个字母,数字,符号等强制执行X长度的密码策略实际上可以通过使密码方案更可预测来减少熵。我同意。Randomess,尽可能真正随机,总是最安全但最不令人难忘的解决方案。

据我所知,制作世界上最好的密码是Catch-22。要么它不令人难忘,太可预测,太短,太多的Unicode字符(在Windows /Mobile设备上难以键入),太长,等等。对于我们的目的来说,没有密码是真正足够好的,所以我们必须保护它们,就好像它们在诺克斯堡一样。

最佳实践

Bcrypt 和 scrypt 是当前的最佳实践。Scrypt在时间上会比bcrypt更好,但它还没有被Linux / Unix或Web服务器采用为标准,也没有对其算法进行深入审查。但是,该算法的未来看起来确实很有希望。如果你正在使用Ruby,有一个scrypt gem可以帮助你,Node.js现在有自己的scrypt包。您可以通过 Scrypt 扩展或 Libsodium 扩展在 PHP 中使用 Scrypt(两者都在 PECL 中可用)。

如果你想了解如何使用bcrypt,或者给自己找一个好的包装器,或者使用像PHPASS这样的东西来实现更传统的实现,我强烈建议阅读crypt函数的文档。我建议至少12轮bcrypt,如果不是15到18轮的话。

当我了解到bcrypt仅使用河豚的密钥时间表时,我改变了使用bcrypt的想法,并具有可变成本机制。后者允许您通过增加河豚已经昂贵的密钥时间表来增加暴力破解密码的成本。

平均做法

我几乎无法想象这种情况了。PHPASS 支持 PHP 3.0.18 到 5.3,因此它几乎可以在可以想象到的每个安装上使用,如果您不确定您的环境是否支持 bcrypt,则应使用 PHPASS。

但假设您根本不能使用bcrypt或PHPASS。然后呢?

尝试使用您的环境/应用程序/用户感知可以容忍的最大轮次数PDKBF2 实现。我建议的最低数字是2500轮。此外,请确保使用 hash_hmac() (如果可用),以使操作更难重现。

未来实践

PHP 5.5中出现了一个完整的密码保护库,它抽象出使用bcrypt的任何痛苦。虽然我们大多数人在大多数常见环境(尤其是共享主机)中都坚持使用 PHP 5.2 和 5.3,但@ircmaxell已经为即将推出的 API 构建了一个兼容层,该层向后兼容 PHP 5.3.7。

密码学回顾和免责声明

实际破解散列密码所需的计算能力并不存在。计算机“破解”密码的唯一方法是重新创建密码并模拟用于保护密码的哈希算法。哈希的速度与其暴力破解的能力呈线性关系。更糟糕的是,大多数哈希算法都可以轻松并行化,以更快地执行。这就是为什么像bcrypt和scrypt这样的昂贵方案如此重要。

您不可能预见到所有威胁或攻击途径,因此您必须尽最大努力预先保护您的用户。如果你不这样做,那么你甚至可能错过你被攻击的事实,直到为时已晚......你有责任。为了避免这种情况,首先要表现出偏执。攻击您自己的软件(内部)并尝试窃取用户凭据,或修改其他用户的帐户或访问其数据。如果您不测试系统的安全性,那么除了您自己之外,您不能责怪任何人。

最后:我不是密码学家。无论我说什么都是我的观点,但我碰巧认为这是基于良好的常识......和大量的阅读。记住,尽可能地偏执,让事情尽可能难以入侵,然后,如果你仍然担心,联系白帽黑客或密码学家,看看他们对你的代码/系统有什么看法。


答案 2

一个更短,更安全的答案 - 根本不写自己的密码机制,使用经过试验和测试的机制。

  • PHP 5.5 或更高版本:password_hash() 质量很好,是 PHP 核心的一部分。
  • PHP 4.x(已过时):OpenWall的phpass库比大多数自定义代码要好得多 - 用于WordPress,Drupal等。

大多数程序员只是没有专业知识来安全地编写加密相关代码而不会引入漏洞。

快速自检:什么是密码拉伸,应该使用多少次迭代?如果您不知道答案,则应使用 ,因为密码拉伸现在是密码机制的关键功能,因为CPU的速度更快,并且使用GPU和FPGA每秒数十亿次猜测的速度破解密码(使用GPU)。password_hash()

截至2012年,您可以使用安装在5台台式PC中的25个GPU在6小时内破解所有8个字符的Windows密码。这是暴力破解,即枚举和检查每个8个字符的Windows密码,包括特殊字符,而不是字典攻击。使用现代GPU,您当然可以破解更多密码或使用更少的GPU - 或者以合理的成本在云中租用GPU几个小时。

还有许多对Windows密码的彩虹表攻击,这些密码在普通CPU上运行并且非常快。

所有这些都是因为Windows仍然不会盐渍或拉伸其密码,即使在Windows 10中也是如此。在2021年,情况仍然如此。不要犯与微软相同的错误!

另请参阅:

  • 优秀的答案,更多关于为什么或是最好的方法。password_hash()phpass
  • 好的博客文章为主要算法(包括bcrypt,scrypt和PBKDF2)提供了推荐的“工作因素”(迭代次数)。

推荐