在MySQL表中存储用户密码的最佳PHP哈希方法是什么?

11

我已经阅读了大约15分钟的Stack Overflow问题,每一个问题似乎都与之前的相矛盾。Bcrypt,SHA1,MD5等等。我目前使用MD5加密密码,但是我想在数据库被攻破时让它变得更加安全。

我知道这个问题已经被问了无数次,但我似乎找不到合适的答案。

谢谢。


可能是PHP密码的安全哈希和盐的重复问题。 - Ilmari Karonen
6个回答

11
你看到矛盾的答案是因为没有正确答案。你应该使用应用程序支持的最安全的方法。更安全=更多开销。 MD5已经被破解。
根据这篇文章,SHA1已经被攻破。但是它还没有被破解。
据我所知,bcrypt尚未被发现存在漏洞。
在足够的CPU周期下,任何哈希或加密算法最终都可以被规避。您的决策应该平衡数据的安全性和应用程序的性能。
鉴于这些警告,bcrypt是目前的事实标准。它专为强度而设计,而不是速度,并且没有被发现存在漏洞。有关bcrypt的信息索引,请参见Wikipedia上的bcrypt文章

6
MD5、SHA1等哈希算法的设计目的是实现快速计算。但是,当用于保护密码时,这并不是最理想的情况。bcrypt算法则被设计成慢速运行(并且可以扩展,以便随着更快的处理器的推出,可以增加其复杂度)。 - Eli
1
Bcrypt 是当前的最佳实践。 - Jacco

9
我会选择bcrypt。它极大地减少了生成彩虹表的能力。
请参考http://codahale.com/how-to-safely-store-a-password/中的内容。
需要注意的是,盐对于防止字典攻击或暴力攻击是无用的。您可以使用巨大的盐或多个盐或手工采摘的、阴凉生长的有机喜马拉雅粉红盐。这不会影响攻击者在获得来自数据库的哈希和盐的情况下尝试候选密码的速度。

2
你遗漏了重要的部分:“_无论是否使用盐,如果你使用的是为速度而设计的通用哈希函数,那么你就真的完蛋了_”。 - MicE
1
+1 为那经常被忽略的喜马拉雅粉红盐点个赞,这是有机成分带来的区别。 - Eddie Parker
经过我自己对这个问题的一些研究,目前的观点似乎是bcrypt在这里是最好的选择。 - Dale
那么,只有在“给定来自您的数据库的哈希和盐”的情况下,攻击者才能破解MD5或SHA1,甚至可能是bcrypt。但是,如果他无法检测到盐是什么,我可以安全地假设我的密码(实际上是它们的盐散列)免受黑客攻击吗? - bad_keypoints
@ronnieaka 不,哈希值不应被视为敏感数据。使用bcrypt时,无论攻击者是否拥有密码的哈希值都无关紧要。 - ceejayoz

2
首先,MD5现在不是一个很好的选择。如果攻击者能够获得您的数据库并获取MD5哈希值,几乎可以肯定他也能够破解它们。弱密码的MD5哈希甚至可以被普通计算机通过暴力破解。
您应该搜索一些关于对哈希进行加盐的文章,并将该方法与更强的哈希算法(至少SHA1)结合使用,可能重复几次该过程。
我不打算写关于加盐的内容,因为已经有很多文章写过了,在Stack Overflow上也可以找到许多有关该问题的好讨论。 例如: 为什么加盐使字典攻击“不可能”?密码盐如何防止彩虹表攻击?

1
当用户注册时,使用以下函数创建一个随机的盐值(salt),例如:salt
$bytes = 50;
$salt = base64_encode(openssl_random_pseudo_bytes($bytes));

将此存储在数据库表中,最好是存储在外部数据库中。然后创建一个随机代码并与您的盐一起存储到外部数据库中。然后将随机代码存储在用户表中,攻击者几乎不可能找到您的盐。

之后,以以下方式存储您的密码:

$password_to_store_in_mysql = hash('sha512', $salt . $user_password);

当用户登录时,从外部数据库中获取盐并检查盐和密码是否匹配。


1
使用MD5、SHA1或任何你想要的加密方式,配合“盐”(SALT)一起使用。
举个例子,我这里只是为了解释而使用MD5。
用户选择一个密码,将其存储在$ password中。
现在创建一个特定于你的应用程序的盐。
$salt = 'my very own salt'; // or maybe make a random string for your salt

然后执行

$more_difficult_password = md5($salt . $password);

这样,如果 MD5 字符串被某种方式泄露,人们就无法通过谷歌搜索来使用字典攻击。

@george 你也可以使用网站的任何秘钥与盐和密码一起..即 md5($secretkey.$salt.$password) - GitsD
1
你还可以保留一个默认的盐,对于每个用户都是相同的,并在用户表中添加一个(我喜欢称之为胡椒^_^)用户特定的盐。这样,您就可以获得更好的加密效果,如果您的数据库被黑客攻击,它将会困扰破解者,因为您已经在整个应用程序中添加了另一个盐。 - Gilly

0

您可以使用网站的密钥和每个用户的特定盐值与您的密码一起使用。您网站的密钥应该保存在数据库中,然后提取并使用。

组合结果如下。

$secret = "your key from database";
$salt = "user salt";// make it randomly
$password = $_POST['password'];

$new_pass = md5($secret.$salt.$password);

现在这些组合将存储在数据库中。

在登录时,再次使用此组合进行匹配。

我认为这可以更好地保护您的应用程序。

Cheers..!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接