当前位置:  开发笔记 > 编程语言 > 正文

为PHP密码保护哈希和盐

如何解决《为PHP密码保护哈希和盐》经验,为你挑选了12个好方法。

目前据说MD5部分不安全.考虑到这一点,我想知道用于密码保护的机制.

这个问题,"双重哈希"密码是否比仅仅哈希一次更安全? 建议多次散列可能是一个好主意,而如何实现单个文件的密码保护?建议使用盐.

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

    散列机制必须在PHP中可用

    它必须是安全的

    它可以使用盐(在这种情况下,所有的盐都同样好吗?有没有办法产生好的盐?)

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

如果我不够清楚,我想知道使用哪种散列函数以及如何选择好的盐以便拥有安全和快速的密码保护机制.

相关问题并不完全涵盖我的问题:

PHP中的SHA和MD5有什么区别
简单密码加密
存储密钥的安全方法,asp.net的密码
如何在Tomcat 5.5中实现salted密码



1> Robert K..:

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

从那以后,PHP给了我们password_hash,password_verify并且,自从他们的介绍,他们是推荐的密码哈希和检查方法.

答案的理论仍然是一个很好的阅读.

TL; DR

注意事项

不要限制用户可以为密码输入的字符数.只有白痴这样做.

不要限制密码的长度.如果您的用户想要一个包含supercalifragilisticexpialidocious的句子,请不要阻止他们使用它.

切勿以纯文本格式存储用户密码.

切勿通过电子邮件将密码发送给您的用户,除非他们丢失了密码,并且您发送了一个临时密码.

永远不要以任何方式记录密码.

永远不要使用SHA1或MD5甚至SHA256 哈希密码!现代的破解者可以分别超过60和1800亿哈希/秒.

不要将bcrypt与hash()的原始输出混合使用,使用hex输出或base64_encode.(这适用于任何可能存在流氓的输入\0,这会严重削弱安全性.)

DOS

尽可能使用scrypt; bcrypt,如果你不能.

如果您不能使用带有SHA2哈希值的bcrypt或scrypt,请使用PBKDF2.

在数据库受到威胁时重置每个人的密码.

实现合理的8-10个字符的最小长度,另外需要至少1个大写字母,1个小写字母,数字和符号.这将改善密码的熵,从而使其更难破解.(请参阅"什么是一个好的密码?"部分进行一些辩论.)

为什么哈希密码呢?

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

您希望在用户帐户上使用良好,健壮的哈希的另一个原因是为您提供足够的时间来更改系统中的所有密码.如果您的数据库受到威胁,您将需要足够的时间来至少锁定系统,如果不更改数据库中的每个密码.

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

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

(强调我的.)

是什么让一个好的密码?

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

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

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

在Crypto StackExchange站点上有一个关于密码熵的更长时间的讨论.良好的Google搜索也会带来很多结果.

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

据我所知,制作世界上最好的密码是Catch-22.它不是难忘的,太可预测的,太短的,太多的unicode字符(难以在Windows /移动设备上键入),太长时间等等.没有密码对我们的目的来说真的足够好,所以我们必须像他们一样保护它们在诺克斯堡.

最佳做法

Bcrypt和scrypt是目前的最佳实践.Scrypt会比bcrypt及时更好,但它还没有被Linux/Unix或网络服务器采用为标准,并且尚未对其发布的算法进行过深入的评论.但是,该算法的未来确实看起来很有希望.如果您正在使用Ruby,那么有一个scrypt gem可以帮助您,Node.js现在有自己的scrypt包.您可以通过Scrypt扩展或Libsodium扩展在PHP中使用Scrypt (两者都在PECL中提供).

我强烈建议您阅读crypt函数的文档,如果您想了解如何使用bcrypt,或者找到一个好的 包装器或使用类似PHPASS的东西来实现更多的遗留实现.我建议至少12轮bcrypt,如果不是15到18.

当我得知bcrypt只使用blowfish的密钥时间表,并使用可变成本机制时,我改变了主意使用bcrypt.后者允许您通过增加blowfish已经很昂贵的密钥安排来增加强制密码的成本.

平均做法

我几乎无法想象这种情况了.PHPASS支持PHP 3.0.18到5.3,因此它几乎可用于所有可以想象的安装 - 如果您不确定您的环境支持bcrypt ,则应该使用它.

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

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

未来的实践

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

密码学回顾与免责声明

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

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

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


一个秘密没有帮助,因为你的密码数据库应该是秘密的 - 如果他们可以获得该数据库,他们也可以找到你正在使用的任何秘密.然而重要的是盐是随机的.
@wicked跳蚤,我不跟你争论.只是指出我们工作的这个领域是多么复杂和复杂.我一直希望通过建立一个小型网站的内容管理系统的最全面,最智能,最好的做法接受教育.我还在这里学习.......每当我读到有意义的东西时,我很快就会注意到其他5个与之相矛盾的帖子.这种圆形的快速令人目不暇接:)
有趣的修改.用户ID(例如,自动增量BIGINT)是一个好的随机数吗?或者因为它不是随机的并不好?此外,我将不得不为数据库中的每个用户存储nonce ...网站密钥+ nonce + HMAC是否提供了多次重复盐渍(带有用户ID)哈希的显着改进的安全性?同样,为了安全性,多次重复使用HMAC?
通过电子邮件发送临时密码,要求用户在第一次使用时更改密码并通过电子邮件发送"安全"链接以允许他们设置密码同样存在风险.在任何一种情况下,任何拦截电子邮件的人都可以访问该帐户,只要他们在预期收件人之前使用该链接或密码即可.
请注意,"解密的计算能力"尚不存在,这并不是真的.由于大多数密码是字典单词或字典派生的,因此基于字典的攻击通常非常有效(因此使用密码策略和迭代计数).
*"即使是MD5仍然是安全的,除了蛮力攻击之外,解密所需的计算能力还不存在."*OMG,我不相信.MD5无法"解密",期间.但它绝对是*不安全的,因为它确实如此.**曾经听过彩虹表吗?**
看,如果你在需要高安全性的软件(如商店)上使用MD5那么你就是傻瓜,而不是我.我知道MD5非常快,但是如果你正在设计具有良好实践的论坛软件,那么它通常仍然是安全的.
我认为即使丢失一个密码也可以通过电子邮件发送新密码是一个坏主意.为什么不通过电子邮件将链接发送到允许用户更改密码的安全网站?这样更舒服(无需在使用随机密码登录后更改密码)并且更加安全,因为没有密码通过未加密的线路 - 请记住,用户很懒,很可能他们不会更改随机密码.
@RobertK通过扩展字符集是增加,但通过强制所有密码遵循规则减少了可能的选项数量.假设有人要通过蛮力获取密码.通过告诉他们用户的密码有1个大写字母,1个小写字母,数字和符号,这意味着他们需要的尝试次数要少得多.通过允许用户决定他们想要什么,黑客必须更加努力.

2> RichVel..:

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

PHP 5.5或更高版本:password_hash()质量很好,是PHP核心的一部分.

较旧的PHP版本:OpenWall的phpass库比大多数自定义代码要好得多 - 在WordPress,Drupal等中使用.

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

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

例如,您可以使用5台台式机中安装的25个GPU 在6小时内破解所有8个字符的Windows密码.这是强制性的,即枚举和检查每个8个字符的Windows密码,包括特殊字符,并且不是字典攻击.那是在2012年,从2018年开始,您可以使用更少的GPU,或者使用25个GPU更快地破解.

对于在普通CPU上运行且非常快的Windows密码,还有许多彩虹表攻击.所有这一切都是因为即使在Windows 10中,Windows 仍然 不会对其密码进行限制或扩展 - 不要像微软那样犯同样的错误!

也可以看看:

优秀的答案,更多关于为什么password_hash()或是phpass最好的方式.

好的博客文章给出了主要算法的推荐'工作因素'(迭代次数),包括bcrypt,scrypt和PBKDF2.


"这些系统更为人所知并且可能已经受到损害" - 没有理由认为设计良好的身份验证系统应该因为它更为人所知而"已经受到损害".像phpass这样的图书馆是由专家编写的,并且被许多人详细审查 - 他们众所周知的事实与不同的人进行详细审查并且更可能意味着他们是安全的.
@PP - 在我看来,具有NSA后门的同行评审密码哈希算法的可能性非常低.不是真正的加密专家的人写一个没有其他漏洞的新密码散列机制的可能性要低得多.典型的webapp只使用MD5或SHA-1哈希,这很糟糕 - 甚至Chris Shiflett的其他伟大的Essential PHP Security书也推荐使用MD5 ......

3> Tom Haigh..:

我不会以两种不同的方式存储密码哈希,因为那时系统至少与使用中最弱的哈希算法一样弱.


对不起,我误解了你的答案,建议使用两个哈希......你其实是正确的.在密码情况下使用两个哈希会削弱系统,因为它们只需要打破较弱的哈希值.

4> Alliterative..:

从PHP 5.5开始,PHP具有简单,安全的函数,用于散列和验证密码,password_hash()和password_verify()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

password_hash()被使用时,它产生一个随机盐和其包括在所输出的哈希值(与成本和使用的算法一起.)password_verify()然后读取该散列并确定使用的盐和加密方法,并验证它靠在提供明文口令.

提供PASSWORD_DEFAULT指示PHP使用已安装的PHP版本的默认哈希算法.究竟哪种算法意味着在未来版本中随时间变化,因此它将始终是最强大的可用算法之一.

增加成本(默认为10)会使散列更难以暴力破解,但也意味着生成散列并验证密码对您的服务器的CPU来说将更加有用.

请注意,即使默认的哈希算法可能会发生变化,旧的哈希值仍会继续验证,因为所使用的算法存储在哈希中并password_verify()在其上进行检测.



5> 小智..:

虽然这个问题已得到解答,但我只想重申,用于散列的盐应该是随机的,而不是像第一个答案中建议的电子邮件地址.

有关更多说明,请访问http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

最近我讨论了用随机位盐渍的密码哈希是否比用可猜测或已知的盐盐渍的更安全.让我们看看:如果存储密码的系统以及存储随机盐的系统受到威胁,攻击者将能够访问哈希以及盐,因此无论盐是否随机,都无关紧要.攻击者可以生成预先计算的彩虹表来破解哈希.这是有趣的部分 - 生成预先计算的表并不是那么简单.让我们以WPA安全模型为例.您的WPA密码实际上从未发送到无线接入点.相反,它与您的SSID(网络名称,如Linksys,Dlink等)进行了散列.这里有一个非常好的解释.要从哈希中检索密码,您需要知道密码以及salt(网络名称).Wifi教会已经预先计算了哈希表,其中包含前1000个SSID和大约100万个密码.所有表的大小约为40 GB.正如您可以在他们的网站上阅读的那样,有人使用了15个FGPA阵列3天来生成这些表.假设受害者使用SSID作为"a387csf3"并将密码用作"123456",那么这些表会被破解吗?没有!.. 这不可以.即使密码较弱,表也没有SSID a387csf3的哈希值.这是随机盐的美丽.它将阻止在预先计算的表格上茁壮成长的破解者.它可以阻止坚定的黑客吗?可能不是.但使用随机盐确实提供了额外的防御层.在讨论这个主题时,让我们讨论在单独的系统上存储随机盐的额外优势.场景#1:密码哈希存储在系统X上,用于哈希的盐值存储在系统Y上.这些盐值是可猜测的或已知的(例如用户名)场景#2:密码哈希值存储在系统X上,盐值用于散列存储在系统Y上.这些盐值是随机的.如果系统X已被泄露,正如您所猜测的那样,在单独的系统上使用随机盐有很大的优势(场景#2).攻击者需要猜测附加值才能破解哈希值.如果使用32位盐,则每个猜测的密码可能需要2 ^ 32 = 4,294,967,296(约42亿)次迭代.


即使攻击者获得了盐,"sitesalt:usersalt:password"字符串仍然可以抵抗预先计算的表,因为攻击者需要为每个用户生成表(因此攻击变得慢得多),除非当然是特定用户正在成为目标......

6> JonoCoetzee..:

我只想指出PHP 5.5包含一个密码散列API,它提供了一个包装器crypt().此API显着简化了散列,验证和重新散列密码哈希的任务.作者还发布了一个兼容包(以你require要使用的单个password.php文件的形式),对于那些使用PHP 5.3.7及更高版本的用户而言,现在想要使用它.

它现在只支持BCRYPT,但它的目的是很容易扩展到包含其他密码散列技术,并且因为技术和成本存储为散列的一部分,对你喜欢的散列技术/成本的改变不会使当前的散列无效,框架将自动化,在验证时使用正确的技术/成本.如果您没有明确定义自己的盐,它还会处理生成"安全"的盐.

API公开了四个功能:

password_get_info() - 返回有关给定哈希的信息

password_hash() - 创建密码哈希

password_needs_rehash() - 检查给定的哈希值是否与给定的选项匹配.用于检查哈希是否符合您当前的技术/成本方案,允许您在必要时进行重新哈希

password_verify() - 验证密码是否与哈希匹配

目前,这些函数接受PASSWORD_BCRYPT和PASSWORD_DEFAULT密码常量,这些密码常量目前是同义词,不同之处在于,当支持更新,更强大的哈希算法时,PASSWORD_DEFAULT"可能会在较新的PHP版本中发生变化." 在登录时使用PASSWORD_DEFAULT和password_needs_rehash()(并在必要时进行重新散列)应确保您的哈希值对蛮力攻击具有相当的弹性,几乎没有工作.

编辑:我刚刚意识到罗伯特K的回答中简要提到了这一点.我将在这里留下这个答案,因为我认为它提供了更多关于它如何工作的信息以及它为那些不了解安全性的人提供的易用性.



7> rabudde..:

我正在使用Phpass,它是一个简单的单文件PHP类,几乎可以在每个PHP项目中轻松实现.另请参见第h.

默认情况下,它使用在Phpass中实现的最强可用加密,它可以bcrypt回退到MD5以外的其他加密,以向Wordpress等框架提供向后兼容性.

返回的哈希可以原样存储在数据库中.生成哈希的示例用法是:

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

要验证密码,可以使用:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);



8> wmfrancia..:

要记住的事情

关于PHP的密码加密已经说了很多,其中大部分是非常好的建议,但在你开始使用PHP进行密码加密的过程之前,请确保你已经实现了以下内容或准备好实现.

服务器

PORTS

无论您的加密有多好,如果您没有正确保护运行PHP和DB的服务器,您的所有努力都毫无价值.大多数服务器的功能相同,它们分配了端口,允许您通过ftp或shell远程访问它们.确保更改了您具有活动状态的远程连接的默认端口.通过不执行此操作,您实际上已使攻击者在访问系统时减少了一步.

用户名

对于世界上所有好的,不要使用用户名admin,root或类似的东西.此外,如果您使用的是基于unix的系统,请不要使root帐户登录可访问,它应该始终只是sudo.

密码

您告诉您的用户制作好的密码以避免被黑客攻击,同样做.当后门敞开时,通过锁定前门的所有努力有什么意义.

数据库

服务器

理想情况下,您希望将DB和APPLICATION放在不同的服务器上.由于成本原因,这并不总是可行的,但它确实允许一些安全性,因为攻击者必须通过两个步骤来完全访问系统.

用户

始终让您的应用程序拥有自己的帐户来访问数据库,并且只为其提供所需的权限.

然后为您提供一个单独的用户帐户,该帐户不存储在服务器上的任何位置,甚至不存储在应用程序中.

像往常一样,不要做这个根或类似的东西.

密码

遵循与所有良好密码相同的准则.也不要在同一系统上的任何SERVER或DB帐户上重复使用相同的密码.

PHP

密码

永远不要在你的数据库中存储密码,而是存储哈希和唯一的盐,我将在后面解释原因.

HASHING

一种方式哈希!!!!!!!,永远不要以可以反转的方式哈希密码,哈希应该是一种方式,这意味着你不要反转它们并将它们与密码进行比较,而是哈希输入的密码以同样的方式比较两个哈希.这意味着即使攻击者可以访问数据库,他也不知道实际的密码是什么,只是它产生的哈希值.这意味着在最糟糕的情况下为您的用户提供更高的安全性.

有很多很好的散列函数在那里(password_hash,hash,等...),但你需要选择一个好的算法散列是有效的.(bcrypt和类似它的是不错的算法.)

当散列速度是关键时,对Brute Force攻击的抵抗力越强.

散列中最常见的错误之一是散列并非用户独有.这主要是因为盐不是唯一产生的.

在散列之前,密码应该总是被腌制.Salting会在密码中添加一个随机字符串,因此类似的密码在数据库中看起来并不相同.但是,如果盐不是每个用户独有的(即:你使用硬编码的盐),那么你的盐几乎没有价值.因为一旦攻击者找到一个密码盐,他就会为所有人提供盐.

创建salt时,请确保它对于密码是唯一的,然后将完成的散列和salt存储在数据库中.这样做是为了让攻击者在获得访问权限之前必须单独破解每个盐和哈希值.这意味着攻击者需要做更多的工作和时间.

用户创建密码

如果用户通过前端创建密码,则意味着必须将密码发送到服务器.这会打开一个安全问题,因为这意味着将未加密的密码发送到服务器,如果攻击者能够监听并访问,那么PHP中的所有安全性都毫无价值.总是安全地传输数据,这是通过SSL完成的,但是即使SSL也没有完美无缺(OpenSSL的Heartbleed漏洞就是这样的一个例子).

同时让用户创建一个安全的密码,它很简单,应该永远完成,用户最终会感激它.

最后,无论您采取的安全措施是否100%安全,保护技术越先进,攻击就越先进.但是,遵循这些步骤将使您的网站更安全,而且不太可能让攻击者追求.

这是一个PHP类,可以轻松地为密码创建哈希和salt

http://git.io/mSJqpw



9> AticusFinch..:

谷歌称PHP可以使用SHA256.

你绝对应该使用盐.我建议使用随机字节(而不是限制自己的字符和数字).通常情况下,选择的时间越长,越安全,越慢.我猜,64字节应该没问题.


对于任何人来说,64位应该足够了吗?

10> Jason OOO..:

我在这里找到了关于这个问题的完美主题:https://crackstation.net/hashing-security.htm,我希望你能从中受益,这里也提供了防止基于时间的攻击的源代码.




11> Max..:

最后,数学上的双重散列不会带来任何好处.然而,在实践中,它对于防止基于彩虹表的攻击是有用的.换句话说,它与使用salt进行散列相比没有什么好处,它可以在您的应用程序或服务器上花费更少的处理器时间.


双哈希不会给你一个显着的优势,但多轮哈希迭代仍然是对字典和布鲁斯力攻击的可行防御.工业强度密码哈希使用1000多轮.PKCS#5的PBKDF1建议最少1000轮.
多重散列还可以防止字典和暴力攻击 - 也就是说它只需要花费更长的时间来计算.

12> rmeador..:

我通常使用SHA1和salt与用户ID(或其他一些用户特定的信息),有时我还使用恒定的盐(所以我有两个部分盐).

SHA1现在也被认为有些受到损害,但程度远远低于MD5.通过使用盐(任何盐),你可以防止使用通用的彩虹表来攻击你的哈希(有些人甚至通过搜索哈希使用谷歌作为一种彩虹表获得了成功).可以想象,攻击者可以使用您的盐生成彩虹表,这就是为什么您应该包含用户特定的盐.这样,他们将不得不为系统中的每个记录生成彩虹表,而不仅仅是整个系统的一个!通过这种类型的腌制,即使是MD5也非常安全.


恒盐不是一个好主意......可能不是一个致命的缺陷,但它不必要地削弱了计划.
推荐阅读
贾志军
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有