目前据说MD5部分不安全 . 考虑到这一点,我想知道使用哪种机制来保护密码 .
这个问题,Is “double hashing” a password less secure than just hashing it once?表明多次散列可能是一个好主意,而How to implement password protection for individual files?建议使用salt .
我正在使用PHP . 我想要一个安全快速的密码加密系统 . 散列密码一百万次可能更安全,但也更慢 . 如何在速度和安全性之间取得良好的 balancer ?另外,我更喜欢结果具有恒定数量的字符 .
-
散列机制必须在PHP中可用
-
一定是安全的
-
它可以使用盐(在这种情况下,所有的盐都同样好吗?有没有办法产生好的盐?)
另外,我应该在数据库中存储两个字段(例如,一个使用MD5,另一个使用SHA)?它会使它更安全或更不安全吗?
如果我不够清楚,我想知道使用哪种散列函数以及如何选择好的盐以便拥有安全快速的密码保护机制 .
相关问题并不完全涵盖我的问题:
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
14 回答
确切地说,我们需要盐盐必须是唯一的,所以让我们生成它
我们也需要使用sha512的哈希它是最好的,它是在PHP中
所以现在我们可以使用这个函数来生成安全密码
现在我们需要在数据库中保存$ hash_psw变量值和$ salt变量
并且为了授权,我们将使用相同的步骤......
这是保护客户密码的最佳方式......
附:对于最后两个步骤,您可以使用自己的算法......但是当您需要授权用户时,请确保将来可以生成此哈希密码...
THINGS TO REMEMBER
关于PHP的密码加密已经说了很多,其中大部分是非常好的建议,但在你开始使用PHP进行密码加密的过程之前,请确保你已经实现了以下内容或准备好实现 .
SERVER
PORTS
无论您的加密有多好,如果您没有正确保护运行PHP和DB的服务器,您的所有努力都毫无 Value . 大多数服务器的功能相同,它们分配了端口,允许您通过ftp或shell远程访问它们 . 确保更改了您处于活动状态的远程连接的默认端口 . 通过不执行此操作,您实际上已使攻击者在访问系统时减少了一步 .
用户名
对于世界上所有好的,不要使用用户名admin,root或类似的东西 . 此外,如果您使用的是基于unix的系统,请不要使root帐户登录可访问,它应该始终只是sudo .
密码
您告诉您的用户制作好的密码以避免被黑客入侵,同样做 . 当后门敞开时,通过锁定前门的所有努力有什么意义 .
DATABASE
服务器
理想情况下,您希望将DB和APPLICATION放在不同的服务器上 . 由于成本原因,这并不总是可行的,但它确实允许一定的安全性,因为攻击者必须通过两个步骤才能完全访问系统 .
用户
始终让您的应用程序拥有自己的帐户来访问数据库,并且只为其提供所需的权限 .
然后为您提供一个单独的用户帐户,该帐户不存储在服务器上的任何位置,甚至不存储在应用程序中 .
像往常一样,不要使这个根或类似的东西 .
密码
遵循与所有良好密码相同的指导原则 . 也不要在同一系统上的任何SERVER或DB帐户上重复使用相同的密码 .
PHP
密码
永远不要在你的数据库中存储密码,而是存储哈希和唯一的盐,我将在后面解释原因 .
HASHING
一种方式哈希!!!!!!!,永远不要以可以反转的方式哈希密码,哈希应该是一种方式,这意味着你不要反转它们并将它们与密码进行比较,而是哈希输入的密码以同样的方式比较两个哈希 . 这意味着即使攻击者可以访问数据库,他也不知道实际的密码是什么,只是它产生的哈希值 . 这意味着在最糟糕的情况下为您的用户提供更高的安全性 .
有很多好的散列函数(
password_hash
,hash
等等),但是你需要选择一个好的算法来使散列有效 . (bcrypt和类似它的是不错的算法 . )当散列速度是关键时,对Brute Force攻击的抵抗力越强 .
散列中最常见的错误之一是散列并非用户独有 . 这主要是因为盐不是唯一产生的 .
盐
在散列之前,密码应该总是被腌制 . Salting会在密码中添加一个随机字符串,因此类似的密码在数据库中看起来并不相同 . 但是,如果每个用户的盐并不是唯一的(即:你使用的是硬编码的盐),那么你的盐就会变得毫无 Value . 因为一旦攻击者找到一个密码盐,他就会有盐对于他们所有人 .
创建salt时,请确保它对于密码是唯一的,然后将完成的散列和salt存储在数据库中 . 这样做是为了让攻击者在获得访问权限之前必须单独破解每个盐和哈希值 . 这意味着攻击者需要做更多的工作和时间 .
用户创建密码
如果用户通过前端创建密码,则意味着必须将密码发送到服务器 . 这会打开一个安全问题,因为这意味着未加密的密码将被发送到服务器,如果攻击者能够监听并访问,那么PHP中的所有安全性都毫无 Value . 总是安全地传输数据,这是通过SSL完成的,但是即使SSL也没有完美无缺(OpenSSL的Heartbleed漏洞就是这样的一个例子) .
同时让用户创建一个安全的密码,它很简单,应该永远完成,用户最终会感激它 .
最后,无论您采取的安全措施是否100%安全,保护技术越先进,攻击就越先进 . 但是,遵循这些步骤将使您的网站更安全,而且不太可能让攻击者追求 .
这是一个PHP类,可以轻松地为密码创建哈希和salt
http://git.io/mSJqpw
虽然问题已得到解答,但我只想重申,用于散列的盐应该是随机的,而不是像第一个答案中建议的电子邮件地址 .
有关更多说明,请致电http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/
我在这里找到了关于这个问题的完美主题:https://crackstation.net/hashing-security.htm,我希望你能从中受益,这里的源代码也可以防止基于时间的攻击 .
我通常使用SHA1和salt与用户ID(或其他一些用户特定的信息),有时我还使用恒定的盐(所以我有2份盐) .
SHA1现在也被认为有些受到损害,但程度远远低于MD5 . 通过使用盐(任何盐),你可以防止使用通用rainbow table攻击你的哈希(有些人甚至通过搜索哈希使用谷歌作为一种彩虹表获得了成功) . 可以想象,攻击者可以使用您的盐生成彩虹表,这就是为什么您应该包含用户特定的盐 . 这样,他们将不得不为系统中的每个记录生成彩虹表,而不仅仅是整个系统的一个!通过这种类型的腌制,即使是MD5也非常安全 .
TL; DR
不要做
不限制用户可以为密码输入的字符数 . 只有白痴这样做 .
Don 't limit the length of a password. If your users want a sentence with supercalifragilisticexpialidocious in it, don' t阻止他们使用它 .
切勿以纯文本格式存储用户密码 .
永远不要将密码通过电子邮件发送给您的用户,除非他们丢失了密码,并且您发送了一个临时密码 .
从不以任何方式记录密码 .
永远不要使用SHA1或MD5甚至SHA256哈希密码! Modern crackers可以超过60和1800亿哈希/秒(分别) .
不要混用bcrypt and with the raw output of hash(),使用十六进制输出或base64_encode它 . (这适用于任何可能包含流氓
\0
的输入,这会严重削弱安全性 . )Dos
尽可能使用scrypt; bcrypt,如果你不能 .
如果您不能使用带有SHA2哈希值的bcrypt或scrypt,请使用PBKDF2 .
在数据库受到威胁时重置每个人的密码 .
实现合理的8-10个字符的最小长度,另外需要至少1个大写字母,1个小写字母,数字和符号 . 这将改善密码的熵,从而使其更难破解 . (有关辩论,请参阅"What makes a good password?"部分 . )
为什么哈希密码呢?
哈希密码背后的目标很简单:通过破坏数据库来防止恶意访问用户帐户 . 因此,密码散列的目标是通过花费太多时间或金钱来计算明文密码来阻止黑客或黑客 . 而时间/成本是你的武器库中最好的威慑力量 .
您希望在用户帐户上使用良好,健壮的哈希的另一个原因是为您提供足够的时间来更改系统中的所有密码 . 如果您的数据库被泄露,您将需要足够的时间来至少锁定系统,如果不更改数据库中的每个密码 .
最近密码恢复之后,Whitehat Security首席技术官Jeremiah Grossman,stated on his blog要求暴力破解他的密码保护:
(强调我的 . )
究竟是什么让一个好的密码?
Entropy . (并不是说我完全赞同兰德尔的观点 . )
简而言之,熵是密码内的变化程度 . 如果密码只是小写罗马字母,则只有26个字符 . 这没有太大的变化 . 字母数字密码更好,有36个字符 . 但允许使用符号的大写和小写大约是96个字符 . 这比仅仅是字母要好得多 . 一个问题是,为了使我们的密码令人难忘,我们插入模式 - 这减少了熵 . 哎呀!
密码熵很容易approximated . 使用全范围的ascii字符(大约96个可键入的字符)产生每个字符6.6的熵,对于未来的安全性,密码的8个字符仍然太低(52.679位的熵) . 但好消息是:更长的密码和带有unicode字符的密码,确实会增加密码的熵并使其更难破解 .
在Crypto StackExchange网站上有更长时间的密码熵讨论 . 一个好的谷歌搜索也会带来很多结果 .
在我与@popnoodles谈过的评论中,他指出强制实施X长度的密码策略,X多个字母,数字,符号等,实际上可以通过使密码方案更具可预测性来减少熵 . 我同意 . Randomess尽可能真正随机,始终是最安全但最难忘的解决方案 .
据我所知,制作世界上最好的密码是Catch-22 . 它不是难忘的,太可预测的,太短的,太多的unicode字符(难以在Windows /移动设备上键入),太长时间等等 . 没有密码对我们的目的来说真的足够好,所以我们必须像他们一样保护他们在诺克斯堡 .
最佳做法
Bcrypt和scrypt是目前最好的做法 . Scrypt会比bcrypt及时更好,但它还没有对其发布的算法进行深入评论 . 但是,算法的未来确实看起来很有希望 . 如果您正在使用Ruby,那么有一个scrypt gem可以帮助您,Node.js现在有自己的scrypt包 . 您可以通过Scrypt扩展名或Libsodium扩展名在PHP中使用Scrypt(两者都在PECL中可用) .
我强烈建议您阅读crypt function的文档,如果您想了解如何使用bcrypt,或者发现自己good wrapper或使用类似PHPASS的内容来获得更多遗留实现 . 我建议至少12轮bcrypt,如果不是15到18 .
当我得知bcrypt只使用河豚的密钥时间表,并使用可变成本机制时,我改变了主意使用bcrypt . 后者允许您通过增加blowfish已经很昂贵的密钥计划来增加强制密码的成本 .
平均做法
我几乎无法想象这种情况了 . PHPASS支持PHP 3.0.18到5.3,因此它几乎可用于所有可以想象的安装 - 如果您不确定您的环境支持bcrypt,则应该使用它 .
但是假设您根本不能使用bcrypt或PHPASS . 然后怎样呢?
尝试使用maximum number of rounds实现PDKBF2,您的环境/应用程序/用户感知可以容忍 . 我推荐的最低数字是2500发 . 此外,请确保使用hash_hmac()(如果可用)以使操作更难以重现 .
未来实践
进入PHP 5.5是full password protection library,它消除了使用bcrypt的任何痛苦 . 虽然我们大多数人在大多数常见环境(特别是共享主机)中都坚持使用PHP 5.2和5.3,但@ircmaxell已经为即将推出的API向@ 5.35向后兼容构建了一个compatibility layer .
密码回顾与免责声明
实际破解散列密码所需的计算能力不存在 . 计算机密码的唯一方法是重新创建密码并模拟用于保护密码的散列算法 . 哈希的速度与其强制的能力线性相关 . 更糟糕的是,大多数哈希算法可以轻松并行化,以便更快地执行 . 这就是像bcrypt和scrypt这样昂贵的计划如此重要的原因 .
您无法预见所有威胁或攻击途径,因此您必须尽最大努力保护您的用户 up front . 如果你不这样做,那么你甚至可能会错过这样一个事实,即你被攻击直到为时已晚......你承担责任 . 为了避免这种情况,首先要采取偏执行为 . 攻击您自己的软件(内部)并尝试窃取用户凭据,或修改其他用户's accounts or access their data. If you don' t测试系统的安全性,然后你不能责怪任何人,除了你自己 .
最后:我不是密码学家 . 无论我说的是我的意见,但我碰巧认为这是基于良好的常识......以及大量的阅读 . 请记住,尽可能偏执,让事情尽可能难以入侵,然后,如果您仍然担心,请联系白帽黑客或密码学家,看看他们对您的代码/系统的看法 .
我不会以两种不同的方式存储密码哈希值,因为那时系统至少与使用中最弱的哈希算法一样弱 .
从PHP 5.5开始,PHP具有简单,安全的函数,用于散列和验证密码,password_hash()和password_verify()
当使用
password_hash()
时,它会生成一个随机盐并将其包含在输出的散列中(连同使用的成本和算法 . )password_verify()
然后读取该散列并确定使用的盐和加密方法,并根据提供的明文密码进行验证 .提供
PASSWORD_DEFAULT
指示PHP使用已安装的PHP版本的默认哈希算法 . 究竟哪种算法意味着在未来版本中随时间变化,因此它将始终是最强大的可用算法之一 .增加成本(默认为10)会使哈希难以暴力,但也意味着生成哈希并验证密码对您的服务器的CPU来说将更加有用 .
请注意,即使默认哈希算法可能会更改,旧哈希仍会继续验证,因为所使用的算法存储在哈希值中并且
password_verify()
会在其上进行检测 .我正在使用Phpass这是一个简单的单文件PHP类,几乎可以在每个PHP项目中轻松实现 . 另见The H .
默认情况下,它使用在Phpass中实现的最强可用加密,即
bcrypt
,并回退到MD5之前的其他加密,以向Wordpress等框架提供向后兼容性 .返回的哈希可以按原样存储在数据库中 . 生成哈希的示例用法是:
要验证密码,可以使用:
谷歌称PHP可以使用SHA256 .
你绝对应该使用盐 . 我建议使用随机字节(而不是限制自己的字符和数字) . 通常情况下,选择的时间越长,越安全,越慢 . 我想,64字节应该没问题 .
一个更短更安全的答案 - don't write your own password mechanism at all ,使用久经考验的机制 .
PHP 5.5或更高版本:password_hash()质量好,是PHP核心的一部分 .
较旧的PHP版本:OpenWall的phpass库比大多数自定义代码要好得多 - 在WordPress,Drupal等中使用 .
大多数程序员都没有专业知识来安全地编写加密相关代码而不会引入漏洞 .
Quick self-test: 什么是密码拉伸和你应该使用多少次迭代?如果您不知道答案,则应使用
password_hash()
,因为密码机制的关键功能现在是密码机制的一个关键特性,因为CPU速度更快,并且使用GPUs and FPGAs以billions of guesses per second(使用GPU)的速率破解密码 .例如,您可以使用5台台式机中安装的25个GPU进行crack all 8-character Windows passwords in 6 hours . 这是强制性的,即枚举和检查每个8个字符的Windows密码,包括特殊字符,并且不是字典攻击 . 那是在2012年,从2018年开始,您可以使用更少的GPU,或者使用25个GPU更快地破解 .
对于在普通CPU上运行且非常快的Windows密码,还有许多彩虹表攻击 . 所有这一切都是因为Windows仍然是doesn't salt or stretch其密码,even in Windows 10 - 不要像微软那样犯同样的错误!
See also:
excellent answer了解更多关于为什么
password_hash()
或phpass
是最好的方式 .good blog article给出了主要算法的推荐'work factors'(迭代次数),包括bcrypt,scrypt和PBKDF2 .
我只想指出PHP 5.5包含一个password hashing API,它提供了一个围绕
crypt()
的包装器 . 此API显着简化了散列,验证和重新散列密码哈希的任务 . 作者还发布了一个compatibility pack(以单个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的回答中提到了这一点 . 我会在这里留下这个答案,因为我认为它提供了更多关于它如何工作的信息以及它为那些不了解安全性的人提供的易用性 .
在可预见的未来,SHA1和一个盐就足够了(当然,取决于你是为Fort Knox编写了一些东西还是购物清单的登录系统) . 如果SHA1不够好,请使用SHA256 .
盐的想法是让哈希结果失去 balancer ,所以说 . 例如,已知空字符串的MD5哈希是
d41d8cd98f00b204e9800998ecf8427e
. 所以,如果有足够内存的人会看到那个哈希并知道它是空字符串的哈希值 . 但是如果字符串被腌制(例如,字符串“MY_PERSONAL_SALT
"), the hash for the 'empty string' (i.e. "MY_PERSONAL_SALT
”)变为aeac2612626724592271634fb14d3ea6
,因此回溯非显而易见 . 我更喜欢使用任何盐,而不是使用盐 . 因此,了解使用哪种盐并不是太重要 .实际上有websites that do just this - 你可以给它一个(md5)哈希,并且它会吐出一个生成该特定哈希的已知明文 . 如果您可以访问存储普通md5哈希值的数据库,那么为这样的服务输入管理员的哈希并登录将是微不足道的 . 但是,如果密码被腌制,这样的服务将成为无效的 .
此外,双散列通常被认为是不好的方法,因为它减少了结果空间 . 所有流行的哈希都是固定长度的 . 因此,您只能拥有此固定长度的有限值,并且结果变得不那么多变 . 这可以被视为另一种形式的腌制,但我不推荐它 .
最后,数学上的双重散列不会带来任何好处 . 然而,在实践中,它对于防止基于彩虹表的攻击是有用的 . 换句话说,它与使用salt进行散列相比没有什么好处,因为在您的应用程序或服务器上占用的处理器时间要少得多 .