5

我在许多文章中读过,我们应该在散列之前将唯一的盐与每个密码结合起来,并将盐存储在数据库中以进行验证,但是将密码本身用作盐怎么样?

这样做会有好处,因为盐对每个人来说都是独一无二的,而且它会被隐藏起来,因为它不会存储在任何地方。

我可以在上面给出的一个简单示例是:

$hashToStore=sha1(strrev($password).$password);

上面我只是反转密码并将其用作盐(我将做一些更复杂的事情,然后只是在开发中反转它。)

这是存储密码的更好方法还是不好的做法。

PS:我完全了解 php 最新的内置功能,例如 crypt()并在现实世界中使用它,但还想对上述内容进行审查。

4

2 回答 2

7

一个常见的错误是在每个哈希中使用相同的盐。盐要么被硬编码到程序中,要么随机生成一次。这是无效的,因为如果两个用户有相同的密码,他们仍然有相同的哈希值。攻击者仍然可以使用反向查找表攻击同时对每个散列进行字典攻击。他们只需要在对密码进行散列之前将盐应用于每个密码猜测。如果盐被硬编码到流行的产品中,可以为该盐构建查找表和彩虹表,以便更容易破解产品生成的哈希。

每次用户创建帐户或更改密码时,都必须生成一个新的随机盐。


[…] 很容易得意忘形,尝试组合不同的哈希函数,希望结果更安全。但是,在实践中,这样做几乎没有什么好处。它所做的只是造成互操作性问题,有时甚至会降低哈希的安全性。永远不要尝试发明自己的加密货币,始终使用专家设计的标准。有些人会争辩说,使用多个散列函数会使计算散列的过程变慢,因此破解会更慢,但有更好的方法可以让破解过程变慢,我们稍后会看到。

以下是我在互联网论坛上看到的一些糟糕的古怪散列函数示例。

md5(sha1(password))
md5(md5(salt) + md5(password))
sha1(sha1(password))
sha1(str_rot13(password + salt))
md5(sha1(md5(md5(password) + sha1(password)) + md5(password)))

不要使用任何这些。


应使用加密安全伪随机数生成器 (CSPRNG) 生成盐。CSPRNG 与普通的伪随机数生成器非常不同,例如“C”语言的 rand() 函数。顾名思义,CSPRNG 被设计为具有加密安全性,这意味着它们提供了高度的随机性并且完全不可预测。我们不希望我们的盐是可预测的,所以我们必须使用 CSPRNG。下表列出了一些流行的编程平台存在的一些 CSPRNG。(PHP:mcrypt_create_iv,openssl_random_pseudo_bytes)

盐需要是每个用户每个密码唯一的。每次用户创建帐户或更改密码时,都应使用新的随机盐对密码进行哈希处理。切勿重复使用盐。盐也需要很长,以便有许多可能的盐。根据经验,让你的盐至少与散列函数的输出一样长。盐应该与哈希一起存储在用户帐户表中。

存储密码

  1. 使用 CSPRNG 生成长随机盐。
  2. 将盐添加到密码中,并使用标准加密散列函数(例如 SHA256)对其进行散列。
  3. 将盐和哈希都保存在用户的数据库记录中。

验证密码

  1. 从数据库中检索用户的盐和哈希。
  2. 将盐添加到给定密码并使用相同的散列函数对其进行散列。
  3. 将给定密码的哈希值与数据库中的哈希值进行比较。如果它们匹配,则密码正确。否则,密码不正确。

在这个页面的底部,有 PHP、C#、Java 和 Ruby 中的加盐密码散列的实现。

在 Web 应用程序中,始终在服务器上散列

如果您正在编写一个 Web 应用程序,您可能想知道在哪里散列。密码应该在用户的浏览器中使用 JavaScript 进行哈希处理,还是应该“以明文形式”发送到服务器并在那里进行哈希处理?

即使您在 JavaScript 中对用户密码进行哈希处理,您仍然需要在服务器上对哈希进行哈希处理。考虑一个网站,它在用户的浏览器中对用户的密码进行哈希处理,而不对服务器上的哈希值进行哈希处理。为了验证用户身份,该网站将接受来自浏览器的哈希值并检查该哈希值是否与数据库中的哈希值完全匹配。这似乎比仅在服务器上散列更安全,因为用户的密码永远不会发送到服务器,但事实并非如此。

问题是客户端哈希逻辑上成为用户的密码。用户进行身份验证所需要做的就是告诉服务器他们密码的哈希值。如果坏人得到了用户的哈希值,他们可以使用它来验证服务器,而无需知道用户的密码!因此,如果坏人以某种方式从这个假设的网站窃取了哈希数据库,他们将可以立即访问每个人的帐户,而无需猜测任何密码。

这并不是说你不应该在浏览器中散列,但如果你这样做了,你绝对也必须在服务器上散列。在浏览器中散列当然是一个好主意,但在您的实现中考虑以下几点:

  • 客户端密码散列不能替代 HTTPS (SSL/TLS)。如果浏览器和服务器之间的连接不安全,中间人可以在下载 JavaScript 代码时对其进行修改,以删除散列功能并获取用户密码。

  • 一些网络浏览器不支持 JavaScript,一些用户在他们的浏览器中禁用 JavaScript。因此,为了获得最大的兼容性,您的应用程序应该检测浏览器是否支持 JavaScript,如果不支持,则在服务器上模拟客户端哈希。

  • 您还需要对客户端哈希进行加盐。显而易见的解决方案是让客户端脚本向服务器询问用户的盐。不要那样做,因为它会让坏人在不知道密码的情况下检查用户名是否有效。由于您也在服务器上进行散列和加盐(使用良好的盐),因此可以使用与特定于站点的字符串(例如域名)连接的用户名(或电子邮件)作为客户端盐。

来源:https ://crackstation.net/hashing-security.htm

所以,回答你的问题,坏主意,非常坏的主意。

于 2014-06-25T18:38:28.133 回答
0

请永远不要这样做。加盐的全部意义在于每个人的密码哈希都是唯一的,这消除了彩虹表的问题并泄露了谁拥有相同的密码。

为什么这很重要?看看他们有“密码提示”的LinkedIn hack。人们有诸如“rhymes with assword”之类的提示,它泄露了他们的密码,以及他们的哈希值。它还泄露了使用相同密码的其他所有人。

于 2014-06-25T18:47:38.677 回答