【问题标题】:Web app passwords: bcrypt and SHA256 (and scrypt)Web 应用程序密码:bcrypt 和 SHA256(和 scrypt)
【发布时间】:2026-01-28 22:10:03
【问题描述】:

在最近(例如 LinkedIn)关于密码的所有讨论中,我正在研究密码哈希实现。在喝了两杯咖啡和早上阅读之后,我不再是一个密码学家了,就像我刚开始时一样。而且我真的不想假装我是。

具体问题

  1. 使用整数唯一用户 ID 作为有效盐会失败吗? (crypt() 只使用 16 位?)

  2. 如果我只是在哈希上一遍又一遍地运行 sha256() 直到用完一秒钟,这是否会击败暴力攻击?

  3. 如果我必须问这些问题,我应该使用 bcrypt 吗?

讨论/解释:

目标很简单,如果我的用户的散列密码被泄露,他们:

  1. 不会“容易”破解,
  2. 破解一个密码不会暴露其他使用相同密码的用户)。

我读到 #1 的内容是哈希计算必须很昂贵——比如说,需要一两秒来计算,并且可能需要一点或内存(以阻止硬件解密)。

bcrypt 内置了这个功能,如果我理解正确的话,scrypt 更具前瞻性,并且包含最低内存使用要求。

但是,通过“重新散列”sha256() 的结果多次以用完几秒钟,然后将最终循环计数与散列一起存储以供以后检查提供的密码?

对于#2,为每个密码使用唯一的盐很重要。尚不清楚盐必须有多随机(或大)。如果目标是避免使用“mypassword”作为密码的每个人都拥有相同的哈希值,那么仅仅这样做还不够吗?:

hash = sha256_hex( unique_user_id + user_supplied_password );

甚至这个,虽然我不确定它能给我带来什么:

hash = sha256_hex( sha256( unique_user_id ) + user_supplied_password );

除了我知道它是独一无二的之外,我可以从使用用户 ID 中看到的唯一好处是避免将盐与哈希一起保存。没有太大的优势。使用用户 ID 作为盐是否存在真正的问题?它没有完成#2吗?

我假设如果有人可以窃取我用户的散列密码,那么我必须假设他们可以得到他们想要的任何东西——包括生成散列的源代码。那么,在散列之前向密码添加一个额外的随机字符串(相同的字符串)有什么好处?那就是:

# app_wide_string = one-time generated, random 64 7-bit *character* string.
hash = sha256_hex( unique_user_id + app_wide_string + user_supplied_password );

我看到了这个建议,但我不明白我从每个用户的盐中获得了什么。如果有人想暴力破解攻击,他们会知道“app_wide_string”并在运行字典攻击时使用它,对吧?

如上所述,是否有充分的理由使用 bcrypt 而不是我自己的滚动?也许我问这些问题的理由就足够了?

顺便说一句——我刚刚在我的笔记本电脑上计时了一个现有的哈希函数,我每秒可以生成大约 7000 个哈希值。不是通常建议的一两秒。

一些相关链接:

using sha256 as hashing and salting with user's ID

SHA512 vs. Blowfish and Bcrypt

What is the optimal length for user password salt?

【问题讨论】:

    标签: encryption passwords hash salt bcrypt


    【解决方案1】:

    Bcrypt 很棒,因为您可以将工作因数从 4 调整到 31,每个增量都会创建一个指数所需的时间,我实际上已经绘制了它,在工作因数为 14 时,它已经占用了一秒钟,所以当计算机得到越来越快,您只需要更改一个参数,当然还要更新您的密码哈希...

    我对 bcrypt 的主要担忧是,如果工作系数设置为高,那么它可能会在多个用户尝试登录时使您的系统过载,因此您可以调整它,具体取决于并发登录的数量和资源你的系统...

    salts 还是需要的,主要目的是阻止离线攻击,如果salt space 太大,那么对手就无法生成查找表,64 位 salt 似乎有点低, bcrypt 具有 128 位盐,再加上工作因素,这对于离线攻击来说是一个相当大的挑战……是的,每个密码的盐应该是随机的,bcrypt 会为你生成一个,如果你对每个密码使用相同的盐,那么你使攻击者更容易使用在线攻击破解所有密码。

    如果你正确设置了工作因子,Bcrypt 真的很适合在线攻击,因为即使我得到了哈希值,意思是说如果“对手”得到了哈希值,工作因子也会让通过整个字典,需要多天,如果密码不在字典中,那么我真的有麻烦了,因为暴力攻击将是史诗般的,bcrypt 的密码位空间虽然有限但相当大:)

    Sha256 现在可能需要一些时间,但最终计算机会变得越来越快,并且很容易受到攻击,unix 人认为 crypt 太慢了,这绝不会成为问题,今天我已经在几秒钟内完成了一次在线攻击,在几天内完成了离线攻击,在几周内完成了一次暴力攻击(遍历整个密码位空间)......

    1. 您希望盐尽可能大且随机,仅使用数字可以让我更轻松地遍历所有可能的 id。
    2. 现在多个 sha256 可能需要一秒钟,但以后它不会再有效了,计算机处理能力呈指数增长,因此您需要一种可以这样配置的算法。
    3. 如果有更多的人这样做,那么您通过提问和做功课来做正确的事,我们就不会有这么多违规行为

    【讨论】:

    • 谢谢。作为后续行动,在散列之前向密码添加“应用程序范围”字符串(如我上面的示例)是否有任何好处?似乎随机盐就足够了,对吗?
    • 它确实使离线(字典和蛮力)攻击变得更加困难,具体取决于熵,因为这些字符串不会被找到,但对于在线攻击没有任何作用,对手也有哈希值作为盐,因为它们必须以纯文本形式保存,以用于验证目的,所以如果您的数据库或您的散列受到损害,那么盐没有多大用处,记住盐阻止离线攻击,工作因素阻止在线攻击,其他问题是哈希冲突,但这是一个相当低的发生率......具有适当工作因素的 bcrypt 应该是好的。
    • 关于第 2 点:重复应用的哈希不能以指数方式缩放吗?我认为它可以,它们可以根据需要应用。例如,今天我应用 sha-512 10^3 次。明天我申请 10^4。
    • @JanusTroelsen 我不确定你所说的point 2 是什么意思,你所描述的不能应用于第 2 点,因为它假设一个常数因子,当然我很模棱两可,至于增加 '因素',您必须正确计算它以匹配 CPU 改进,即使在使用 bcrypt 时您仍然必须这样做,但它已经为此进行了很好的调整。最终,CPU 将改进到我们可以遍历整个位空间的程度,到那时我们会想出别的东西(希望如此)......
    • 这个答案是一个有用的开始,但可以通过 1) 定义“在线”与“离线”攻击来改进(如此处的意思 - 通常这些术语表示某人是否连接到互联网,但我认为你的意思是别的); 2)解释为什么“app-wide”字符串有帮助(我认为只有当攻击提供对数据库而不是代码的访问时才会这样做); 3) 根据 Janus Troelsen 的评论,bcrypt 的调整参数比用作控制 SHA256 应用程序数量的指数的单个参数更容易(或更好)使用。
    【解决方案2】:

    使用整数唯一用户 ID 作为有效盐会失败吗? (crypt() 只使用 16 位?)

    您通常会使用随机生成的盐,然后将该哈希与加密密码一起存储。攻击者也可以访问盐并不重要——它的目的是防止使用查找表,从而迫使攻击者单独暴力破解每个哈希。

    crypt 只是将盐和哈希以及要使用的算法存储到一个字符串中。

    【讨论】:

    • 我认为盐的唯一用户 ID 的问题是攻击者可能对每个盐都有一个单独的查找表,如果盐是一个长随机字符串,这将是不可行的。
    • 他仍然需要每个 id 单独的表。除非这种方案足够普遍,以至于每个攻击者都有几十万个预先生成的查找表,否则不会有任何收益。
    最近更新 更多