【问题标题】:Can someone explain how to do password hashing + salting有人可以解释如何进行密码散列+加盐吗
【发布时间】:2011-09-07 12:29:33
【问题描述】:

我在 SO(以及在我尝试进一步研究后在 Google 上找到的其他网站)上读到,将密码存储在数据库中的正确安全方法是存储 a密码。最重要的是,每个用户的盐应该是不同的,这样即使他们有加密的值,黑客也不会造成伤害。

我不太清楚加盐是什么意思。根据我的理解,您对密码进行哈希处理,然后使用哈希处理的另一个值(盐)并将这两者结合在一起,因此每个用户检索原始密码的算法都不同。

所以基本上,我要做的是对密码进行哈希处理,然后对每个用户的不同值使用不同的哈希值(即:用户名或电子邮件地址),然后我可以对这两个值来获取编码的密码。

这是正确的,还是我只是对密码哈希 + 加盐一无所知?

一个简单的解释或示例会很有帮助,因为我发现的网站并不能清楚地解释什么是加盐密码。

编辑:在阅读了到目前为止留下的 cmets 和答案后,我明白我并没有真正理解什么是盐,因为我遗漏了一些关键概念并且我做出了错误的假设。

我想知道的是:如果它是随机生成的,您如何始终获得相同的盐?如果盐像某些人提到的那样存储在数据库中,那么我可以看到您如何不断获得相同的盐,但这带来了另一个问题:如果有权访问数据库的任何人都可以访问,它如何使密码更安全?盐?难道他们不能只是将(已知的)盐附加到他们尝试的所有密码中,结果会与根本没有一个相同(除了一些小的时间损失)吗?

【问题讨论】:

  • 我在查看 Google 时阅读了第一篇文章,但无法弄清楚它们是如何以一致的方式生成随机位的(如果它是随机的,那么当您尝试对 salt 进行身份验证时)不会相同,因此它不起作用)。那是我不太明白的,我认为这些位一定是从其他地方生成的。
  • 相关,但不是直接的答案:现在用于安全存储密码的常用方法是使用 bcrypt en.wikipedia.org/wiki/Bcrypt,它使用公共盐存储密码。安全性在于加密密码的速度很慢,因此暴力攻击更加耗时。

标签: sql security hash salt


【解决方案1】:

让我试着用一个有点过于简单的例子来澄清一下。 (md5() 仅用于示例目的 - 您应该在实践中使用它。)

盐只是在散列之前附加到密码的随机字符串。假设您有密码letmein,然后像这样散列它...

 echo md5('letmein')

...您将获得输出0d107d09f5bbe40cade3de5c71e9e9b7。如果你是google this,你会看到很多页面告诉你这是letmein 的MD5 哈希值。盐旨在帮助防止此类事情发生。

假设您有一个函数randomStringGenerator(),它生成一个随机的$x 字符串。要使用它来加盐密码,您可以执行以下操作:

 $password = 'letmein';
 $salt = randomStringGenerator(64); //let's pretend this is 747B517C80567D86906CD28443B992209B8EC601A74A2D18E5E80070703C5F49

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

然后您将执行md5(letmein747B517C80567D86906CD28443B992209B8EC601A74A2D18E5E80070703C5F49),它返回af7cbbc1eacf780e70344af1a4b16698which can't be "looked up" 就像不加盐的letmein 一样容易。

然后您将存储哈希和盐,当用户输入密码登录时,您将重复上述过程并查看用户输入的密码是否附加了存储的盐的哈希到与存储的哈希相同。

但是! 由于像 MD5 和 SHA2 这样的通用哈希算法非常快,you shouldn't use 它们用于存储密码。查看 phpass 了解 bcrypt 的 PHP 实现。

希望有帮助!

【讨论】:

  • 它确实有很大帮助,现在我了解(我认为主要是)它是如何工作的,但是如果你阅读我的 OP 末尾的编辑部分,我仍然不明白它是如何产生的如果盐在表中,则密码加密更安全。他们不能尝试常规的暴力破解并尝试 a.salt、b.salt 等吗?
  • @Adam Smith:让我们试试这个:加盐唯一能做的就是增加破解单个密码所需的时间。通过为每个密码使用不同的盐,您实际上会导致黑客创建一个彩虹表每个密码,而不是一个可用于整个数据库的彩虹表。
  • @Adam Smith:当然!它根本无法防止暴力攻击(使密码变长可能会使计算散列的时间变长,但还不够重要)。这就是为什么您要使用设计为 的散列算法,例如 bcrypt,而不是每秒可以执行数亿次的散列算法,例如 MD5 或 SHA2。
  • 现在说得通了。非常感谢!我想我错过了几个关键概念来真正理解它是如何工作的,我很高兴你能帮助我理解它,非常感谢你的帮助!
【解决方案2】:

使用盐来避免攻击者创建 彩虹表,例如包含所有(通常)密码和相应哈希值的表,按哈希值排序(或以某种方式易于访问)。如果攻击者拥有或可以创建这样的表,然后使用未加盐的哈希获取您的密码数据库,他可以轻松查找密码,甚至可以同时查找您的所有用户。

如果散列被加盐(并且攻击者通过散列得到盐),他仍然可以进行相同的攻击(只需要稍微多一点的工作来输入盐) - 但现在这项构建彩虹的工作table 对于下一个使用另一种盐的哈希是无用的,这意味着需要再次为每个用户完成此操作。 仅此就是盐的目标。对你的单个帐户的字典攻击仍然需要和以前一样的时间,只是彩虹表没用。 (要对字典攻击做些什么,见下文。)


盐的使用方式取决于所使用的算法。一些散列算法(例如专门为密码散列而制作的 bcrypt)具有特殊的 salt 输入参数(或自己生成 salt 并将其包含在输出中):

H = bcrypt(密码,硬度)或 H = bcrypt(盐,密码,硬度)

(第一个变体自己生成盐,而第二个变体从外部获取盐。两者都在输出中包含哈希和硬度参数。)

其他的需要在一些特殊的模式下才能使用盐。 一个适用于大多数哈希算法的简单变体是使用HMAC,将盐作为“消息”输入,密码作为密钥:

HMAC(password, salt) = Hash(password ⊕ opad || Hash(ipad ⊕ password || salt) )

其中 opad 和 ipad 是一些恒定的填充值。

然后将盐与哈希一起存储。 (对于稍高的障碍,您可以将哈希存储在盐以外的另一个位置。但您仍然需要两者来登录。)对于登录,您将密码和存储的盐提供给您的哈希函数,并比较结果与存储的哈希。 (大多数 bcrypt 库都内置了“密码验证”功能。)


对于密码存储,重要的是使用慢速散列算法,而不是快速散列算法,以避免(或实际上:减慢)密码的暴力破解或字典攻击,大多数人都会这样做密码很短。 bcrypt 是专门为这个目标而设计的算法(它的慢度可以通过一个参数来调整)。

如果您使用快速散列函数,请务必重复多次以再次变慢。 (但更好,真的:使用 bcrypt。)

【讨论】:

    【解决方案3】:

    虽然@Chris 和@Pualo 有很好的答案。我想再补充一件关于对尚未表达的密码进行加盐的事情。

    加盐密码并不是真正的保护机制。无论您使用的是 bcrypt 还是任何其他机制都没有关系。这只是一种拖延战术,仅此而已。

    通过对每个密码使用不同的盐值,您会迫使黑客为每个密码创建一个彩虹表以破解它们。这增加了所需的时间,但绝不会使其成为不可能。请记住,使用基于云的计算,您可以启动大量机器来创建彩虹表,并且您可以看到延迟非常小。

    此外,大多数僵尸机器都可以出租......

    也就是说,你经历麻烦的原因是为了争取时间。是时候注意到您已被破坏,修复它并通知您的用户违反了。而已。

    如果攻击者获得了对您数据库的足够访问权限以提取密码列表,那么几乎可以保证他们已经获得了其他所有内容。所以,此时你已经失去了一切。唯一的问题是您需要多长时间才能堵住漏洞,重置每个人的密码,并告诉他们应该重置他们可能拥有的任何其他帐户的密码,而他们可能使用相同的帐户。如果你是 Sony,那么这个时间显然是用几个月来衡量的,如果不是几年的话……;) 试着比这快一点。

    因此,尽管这样做是负责任的事情,但它只是您防御工具带的一部分。如果您遭到破坏,那么您可以打赌这些用户名和密码将在不久的将来某个时候出现在某个站点上。希望在那之前你已经把你的房子打扫干净了。

    【讨论】:

    • 我很高兴你也回答了我没有说的话。正如您所说,它只是我防御工具带中的一种工具;您是否有一个链接可以向我推荐其他良好做法以确保我的数据安全或其他我应该注意的事项?
    • @Adam Smith:从这里开始:owasp.org 具体来说,owasp.org/index.php/Category:Principle
    • 使用 bcrypt 您可以指定成本。每个密码几年就够了吗?不要将其与消息哈希归为同一类别或将其视为“只是一种延迟策略”。
    • @ErikE: 当然...如果您的用户想花那么长时间登录您的网站...您必须保持足够低的成本以使您的网站在您的硬件上保持响应 。以这种方式考虑,假设我是一名黑客,我在一个僵尸网络上租用时间,这让我可以访问十万台机器。即使每个哈希的成本是 5 秒(这对于登录网站来说是很长的时间),这意味着我每分钟可以生成 200 万个密钥。我想知道,我必须生成多少才能发生碰撞?鉴于大多数人使用的密码,我想说的不多。
    • @ErikE:另外,不要提出用数字代替字母等。常见(甚至不常见)的数字已成为字典的一部分。
    【解决方案4】:

    使用 salt 可以防止使用预先计算的彩虹表,例如,如果用户使用“Password”作为密码,MD5(“Password”)、SHA1(“Password”) 或 WhatEver(“Password”) 可能会很好- 已知结果存储在一些彩虹表中。 如果你对每个人使用不同的盐值——称为随机数——你会得到 MD5(HMAC("Password","RandomSaltValue")), SHA1("Password","AnotherRandomSaltValue"), ... 这意味着两个不同的相同初始密码的哈希密码值。 现在关于存储这些盐值的问题......我认为它们可以存储到数据库中,盐的想法是防止彩虹式攻击,而不是数据库受损问题。

    【讨论】:

    • 我明白了,所以在你的密码上使用盐并不能真正帮助再次迭代每个可能值的暴力破解技术,它是为了保护你免受字典攻击等。这是有道理的,我认为加盐也可以保护密码免受常规暴力破解。这就解释了存储的盐并没有真正造成额外的安全漏洞。
    【解决方案5】:

    尽管bcrypt 大大减慢了进程,但如果可以并行进行大量计算,攻击您的方案仍然可能是可行的。我知道这不太可能,这确实是一个足智多谋的攻击者,但让我们假设您保护的站点将包含来自 51 区的照片和文档 :) 在这种情况下,如果有足够的并行化,即使使用bcrypt.

    这就是我喜欢scrypt 方法的原因——它不仅涉及计算成本,而且还施加了内存限制,特别是在空间方面引入成本并使此类并行攻击不可行。我只能推荐阅读该网站上链接的论文,它很好地说明了这个概念。

    虽然,似乎bcrypt 甚至更多的scrypt 在密码分析方面受到的关注似乎比 RSA 的 PKCS#5 中概述的 PBKDF2 少。有关详细信息,请参阅此discussion

    【讨论】:

      【解决方案6】:

      首先我想说的是,安全性很难做到正确,您确实应该依靠现有的库来为您做尽可能多的事情。对于密码存储和验证等基本操作,这绝对是正确的。

      编辑:删除了错误信息。我会坚持我唯一的好建议,那就是不要自己动手。

      【讨论】:

      • 所有可能的盐值?您确定吗?对我来说似乎有点不对劲。
      • 如果它尝试所有可能的盐值并且盐被异或合并,它将适用于每个密码。
      • 我会为此 +1对你来说。但是你的“蛮力登录”想法是-1。
      • @Emdot:嗯...不。盐被储存。它通常与密码本身存储在同一记录中。当用户输入他们的密码时,您获取密码并将其与盐结合并对其进行哈希处理。然后你比较哈希值。如果他们匹配你很高兴去。系统不会比较所有可能的哈希值以查看输入的密码是否正确。这将花费太长时间。
      • @Adam:加盐只是为了帮助彩虹表(例如,有人预先计算了所有密码的哈希值,然后简单地从哈希值中查找密码)。使用盐,攻击者必须为每个正在使用的盐创建一个彩虹表(或为所有盐创建一个彩虹表,如果盐足够长,它会变得比地球上的存储容量大)。
      【解决方案7】:

      Secure hash and salt for PHP passwords 呢?它甚至还有 PHP 示例。

      【讨论】:

      • @Paŭlo Ebermann “请不要留下应该是 cmets 的答案。答案应该试图回答问题。” - 我的回答没有回答问题吗?我还以为再把文字复制到这里不是个好主意。
      • 实际上,最好的方法是在链接到该问题时将问题标记为关闭。本质上是一样的。 SO 会自动将其附加为注释。
      • 我有,但是我缺少一些关键概念,例如如何始终如一地获得相同的盐(即随机生成的)。似乎它已被存储,因此可以回答我的问题,但是如果尝试破解密码的人已经有了盐,那么它的安全性如何?
      猜你喜欢
      • 1970-01-01
      • 2011-06-02
      • 2016-10-22
      • 2015-02-17
      • 2015-10-08
      • 2018-11-20
      • 2015-08-20
      • 1970-01-01
      • 2012-05-28
      相关资源
      最近更新 更多