目前称MD5部分不安全.考虑到这一点,我想知道使用哪种机制来保护密码.

这个问题,Is “double hashing” a password less secure than just hashing it once?

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

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

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

如果我不够清楚,我想知道应该使用哪个散列函数,以及如何 Select 一个好的salt,以便拥有一个安全、快速的密码保护机制.

Related questions that don't quite cover my question:

What's the difference between SHA and MD5 in PHP
Simple Password Encryption
Secure methods of storing keys, passwords for asp.net
How would you implement salted passwords in Tomcat 5.5

推荐答案

DISCLAIMER:这个答案写在2008年.

从那时起,PHP给了我们password_hashpassword_verify,自从它们被引入以来,它们就是推荐的密码散列和校验方法.

不过,答案的理论仍然是一本不错的读物.

TL;博士

不要这样做

  • 不要限制用户可以输入的密码字符.只有傻瓜才会这么做.
  • 不要限制密码的长度.如果你的用户想要一个句子中包含超动词短语,不要阻止他们使用它.
  • 不要剥离或转义密码中的HTML和特殊字符.
  • 永远不要以纯文本形式存储用户密码.
  • 永远不要通过邮箱向用户发送密码
  • 永远不要以任何方式记录密码.
  • 千万不要用SHA1或MD5甚至SHA256散列密码!Modern crackers可以分别超过每秒600亿和1800亿个哈希.
  • 不要混用bcrypt and with the raw output of hash(),要么使用祸不单行输出,要么使用base64_encode.(这适用于任何可能包含流氓\0的输入,这可能会严重削弱安全性.)

DOS

  • 如果可以,请使用sccrypt;如果不能,请使用bcrypt.
  • 如果不能使用bcrypt或scrypt,请使用PBKDF2和SHA2哈希.
  • 当数据库被 destruct 时,重置每个人的密码.
  • 实现合理的8-10个字符的最小长度,外加要求至少1个大写字母、1个小写字母、一个数字和一个符号.这将提高密码的熵,进而使其更难破解.(请参阅"什么才是好的密码?"部分进行一些辩论.)

为什么还要散列密码?

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

您需要对用户帐户进行良好、健壮的散列的另一个原因是给您足够的时间来更改系统中的所有密码.如果您的数据库遭到 destruct ,您将需要足够的时间将系统锁定在least,如果不能更改数据库中的每个密码的话.

Whitehat Security首席技术官杰里米·格罗斯曼(Jeremiah Grossman)在最近一次密码恢复后stated on White Hat Security blog岁,这需要暴力破解他的密码保护:

有趣的是,在经历这场噩梦的过程中,我学到了很多我不知道的关于密码破解、存储和复杂性的知识.I’ve come to appreciate why password storage is ever so much more important than password complexity. If you don’t know how your password is stored, then all you really can depend upon is complexity.对于密码和加密专家来说,这可能是常识,但对于一般的信息安全或网络安全专家来说,我非常怀疑这一点.

(我的)

What makes a good password anyway?

Entropy.(我并不完全同意兰德尔的观点.)

简而言之,熵是密码中的变化量.当密码只有小写罗马字母时,只有26个字符.这并不是很大的变化.字母数字密码更好,有36个字符.但允许大写和小写字母加上符号,大约是96个字符.这比只写字母要好得多.一个问题是,为了让我们的密码令人难忘,我们插入了减少熵的模式.哎呀!

密码熵很容易达到approximated.使用全范围的ASCII字符(大约96个可打字字符)会产生每个字符6.6%的熵,8个字符的密码对于将来的安全性来说仍然太低(52.679比特的熵).但好消息是:更长的密码和带有Unicode字符的密码确实增加了密码的熵,使其更难破解.

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

在 comments 中,我与@popfacles交谈,他指出,enforcing长度为X的密码策略包含X个字母、数字、符号等,通过使密码方案更具可预测性,实际上可以减少熵.我确实同意.Randomess,尽可能地随机,总是最安全但最不令人难忘的解决方案.

就我所知,打造世界上最好的密码是一个难题.要么它不值得记忆,要么太容易预测,要么太短,要么太多unicode字符(在Windows/Mobile设备上很难键入),要么太长,等等.没有任何密码能真正满足我们的目的,所以我们必须像在诺克斯堡一样保护它们.

最佳实践

Bcrypt和scrypt是当前的最佳实践.Scrypt将在时间上优于bcrypt,但它还没有被Linux/Unix或Web服务器视为标准,也没有发布对其算法的深入审查.但尽管如此,该算法的future 看起来还是很有希望的.如果你正在使用Ruby,有一个scrypt gem可以帮你解决这个问题,还有Node.js现在有了自己的scrypt包.您可以通过Scrypt扩展或Libsodium扩展在PHP中使用Scrypt(这两个扩展在PECL中都可用).

如果您想了解如何使用bcrypt,我强烈建议您阅读crypt function的文档,或者给自己找一个good wrapper,或者使用类似PHPASS的东西来实现更传统的实现.我建议至少12轮加密,如果不是15到18轮的话.

当我了解到bcrypt只使用河豚的密钥表时,我改变了使用bcrypt的主意,并且采用了可变成本机制.后者允许您通过增加河豚本已昂贵的密钥时间表来增加暴力破解密码的成本.

一般做法

我几乎不能再想象这种情况了.PHPASS支持PHP 3.0.18到5.3,因此它可以在几乎所有可以想象到的安装上使用-如果您不支持know for certain,并且您的环境支持bcrypt,则应该使用它.

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

try 使用您的环境/应用程序/用户感知可以容忍的maximum number of rounds实现PDKBF2.我推荐的最低数量是2500发.此外,如果hash_hmac()可用,请确保使用hash_hmac(),以使操作更难重现.

future 的做法

PHP5.5是一个full password protection library,它可以消除使用bcrypt的任何痛苦.虽然我们大多数人在最常见的环境中,尤其是在共享主机中,仍然坚持使用PHP5.2和5.3,但@ircmaxell为即将到来的API构建了一个compatibility layer,该API与PHP5.3.7向后兼容.

Cryptography Recap & Disclaimer

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

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

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

Php相关问答推荐

带有打印和回声的PHP意外命令

如何使用属性#[Embedded]嵌入带有规则的对象集合?

自定义通知在Woocommerce我的帐户自定义端点页面上不起作用

如何在不指定symfony列的情况下从数据库中获取行数组

WooCommerce基于元数据的自定义范围目录排序

多行PHP属性声明中是否允许单行注释

带Redhat php curl的http_code 0

按列值将二维数组排序为不超过N个的递增组

在php中,方法之间的属性链接是如何工作的

将数据推入所有子数组条目

无法在 WordPress 上获取 JSON 数据

PHP 数组中第一级 node 到 XML 的唯一名称

在 WooCommerce 中何时何地执行 woocommerce_order_status_completed_notification 挂钩?

如何限制 woocommerce 中相关产品的标题长度

AWS S3:当对象名称包含 % 时复制对象失败并出现错误 - 无效的复制源编码

由于 PHP 版本不受支持,如何终止 PHP 脚本?

如何在 PHP 中对具有相同数组值的值求和

如何在 laravel 中的同一个 slug 上显示不同的内容?

如何通过额外的属性和本地化来使用 laravel 枚举

使用循环和引用而不是递归创建分层/父子数组