我应该把盐和散列密码一起存储在数据库中吗?


Should I store my salt along with my hashed password in the database?

我已经阅读了一堆关于安全性的东西,我现在才开始尝试使用代码。我想用加盐的MD5加密。我偶然发现了这个漂亮的PHP脚本:

substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',5)),0,10);

它随机生成一些字符作为salt,但后来我在想:我该如何检查登录?我应该去掉这些盐,还是应该把它们存储在数据库中?

您不应该使用MD5进行密码散列。查看如何存储我的用户'密码安全吗?

为了回答你最初的问题,盐与哈希密码一起存储在数据库中。如果散列密码被发现,盐并不意味着是秘密的。其目的是防止攻击者使用彩虹表。

存入数据库。否则,您无法将用户提供的密码与散列密码进行比较。

有些甚至在给定用户每次成功登录时重新生成哈希(使用新的盐),尽管下面的评论认为这不是最好的主意(参见评论)

好吧,所以盐既用于单向哈希又用于加密。它们使加密或散列更难逆转。我认为用哈希更容易指出这一点,所以我将从这个角度来写,但这些原则适用于一般的加密。

想象你正在保存密码。您的一个用户选择单词"kiwi"作为密码。因为以明文形式存储密码是愚蠢的,所以您不会想要这样做。您想要散列密码

但是,那些讨厌的黑客已经编译了巨大的数据库的哈希查找表。(看看这个!)

那么,我们如何挫败黑客呢?通过盐渍用户的输入!盐是一个随机字符串(或一组比特,正确地说),它与用户的输入进行加密组合,以产生更安全的哈希。

例如,如果要散列的字符串仍然是"kiwi",而我们的盐是"5m3d",一个简单的盐机制可以将两者连接成:"kiwi5m3d"。黑客可能在他们的数据库中有"kiwi",但可能没有"kiwi5m3d"。一个好的腌制系统可能会执行比这复杂得多的功能。

所以现在黑客需要为每个可能的盐建立一个新的查找数据库。使用随机盐意味着黑客将不得不进行全面的蛮力攻击,而不是重复以前的计算或使用其他人的查找表。

你可以为所有东西选择不同的盐,或者为你网站上的所有东西选择相同的盐。每个实体的不同盐需要对每个实体进行新的蛮力攻击,但它可以使实现变得更加困难,因为每个盐必须保存,而不是一个全局盐(对于已经有些随机的数据,例如密码,应该足够)。

在加密的情况下,查找表仍然是一种可能性,但要加密的数据通常变化很大,因此它们是不可行的。所以它变成了一个"猜密码"的游戏。"kiwi"很容易猜,"kiwi5m3d"很难猜。

必须将盐保存在某个地方,因为这是"知道"被散列或加密的内容的唯一方法。在散列的情况下,将用户的原始散列与他们输入的加盐散列进行比较。在加密的情况下,您需要盐来解密数据。

你要去哪里?首先,不要使用MD5。上面我给了你一个MD5查找数据库的链接。这个函数越来越被认为是弱的。sha类算法是一个较好的选择。

第二,确保你选择了一种好的盐。越长越随机越好。计算机不太擅长生成随机数据。这个网站可能是一个不错的选择,它对如何生成随机数有一个很好的分解。

第三,考虑盐算法。简单的连接应该可以工作,但也许HMAC(我不太了解的东西)会更好。

您必须将其存储在数据库中,否则您将没有任何东西可以与之进行比较。使用盐时要记住的是,复杂性是可以变化的,如果不知道盐是什么,它被暴力破解的可能性就会大大降低。

的例子:

$password = "banana";
$salt = "a12dsfg33B1cD2eF3G"; # Can be any assortment of characters
$password = md5($salt.$password);

然后您只需附加相同的salt(必须匹配才能工作)并将相同的函数传递给结合了salt和提供的密码的登录脚本。然后将该值与数据库中的值进行核对,以验证用户的身份。

不要发明您自己的密码散列方案,无论它看起来多么漂亮。拥有一个安全的系统是很困难的,因为您无法真正测试安全性。您需要的是:

  • 为每个密码实例创建一个足够长度的随机盐。
  • 随机盐沿散列值存储;您将需要它验证密码之后。
  • 密码哈希过程必须是(可配置的)缓慢的,有许多(许多)嵌套调用内部使用的任何哈希函数。
  • 最好,内部哈希函数应该使用在PC上高效但在并行架构(GPU)上缓慢的操作。

这样的东西是存在的,它被称为bcrypt,你可以在PHP中使用便携式PHP密码散列框架获得它。