Security 可以用迭代散列代替每个用户的随机分组吗?

Security 可以用迭代散列代替每个用户的随机分组吗?,security,authentication,encryption,cryptography,Security,Authentication,Encryption,Cryptography,在构建我所希望的正确架构的身份验证机制的过程中,我遇到了许多材料,其中规定: 用户密码必须加盐 使用的盐应足够随机,并按用户生成 …因此,salt必须与用户记录一起存储,以支持用户密码验证 我完全同意第一点和第二点,但后者似乎有一个简单的解决办法。而不是执行(此处为伪代码)的等效操作: 为什么不使用用户名的哈希作为salt?这就产生了一个分布均匀(大致)随机的盐域,每个盐都像盐函数所提供的那样复杂。更好的是,您不必将salt存储在数据库中,只需在身份验证时重新生成它。更多伪代码: salt =

在构建我所希望的正确架构的身份验证机制的过程中,我遇到了许多材料,其中规定:

  • 用户密码必须加盐
  • 使用的盐应足够随机,并按用户生成
  • …因此,salt必须与用户记录一起存储,以支持用户密码验证
  • 我完全同意第一点和第二点,但后者似乎有一个简单的解决办法。而不是执行(此处为伪代码)的等效操作:

    为什么不使用用户名的哈希作为salt?这就产生了一个分布均匀(大致)随机的盐域,每个盐都像盐函数所提供的那样复杂。更好的是,您不必将salt存储在数据库中,只需在身份验证时重新生成它。更多伪代码:

    salt = hash(username);
    hashedPassword = hash(salt . password);
    storeUserRecord(username, hashedPassword);
    
    (当然,上面示例中的
    散列
    应该是合理的,比如SHA-512或其他强散列。)

    考虑到我对加密的了解(很少),这对我来说似乎是合理的,但事实上,这是对广泛推荐的做法的简化,这让我想知道是否有一些明显的原因我误入歧途,但我不知道

    编辑有些人似乎不知道问题是什么。我决不是建议不要用盐。参考TheRook编辑的答案:我熟悉那些CWE中提到的参考文献。我的核心问题是:为什么散列(用户名)是可预测的salt


    编辑2感谢所有提供答案的人;biffabacon在他的第2段中直接提到了我的核心问题(基本上,你可以做任何事情来最大化使用的SALT的域,因此生成的哈希密码都是好的),但是在关于这个问题的各种评论中有很多有趣的信息。

    SALT的原因是为了防止密码分析攻击。每个用户的唯一salt意味着您无法判断两个用户是否具有相同的密码。每个用户的salt不确定意味着您无法判断是否在两个系统上使用相同的username:password


    不要试图胜过盐。如果您不愿意使用这些空间,那么就不要使用它们,而是直接将精力投入到保护您的数据(和备份!)

    salt有助于防止攻击者使用预计算或字典攻击。使用salt时,攻击者需要为每个salt值创建单独的字典。但是,如果salt不是随机的,那么攻击者就有了优势,因为他们可以创建比其他人更可能创建的词典。例如,他们可以使用jsmith的salt(或jsmith的hash)创建字典。出于这个原因,一般来说,盐是随机的是一个好主意


    比较针对散列(用户名)salt和随机salt的预计算攻击:例如,攻击者决定为最常见的1000个用户名和六个不同的散列ALG创建字典;那是6000种盐和6000本字典。如果使用随机32位salt,则为2^32或大约42亿个字典。因此,当salt空间显著减少时(就像使用hash(username))预计算攻击变得更加可行

    salt的目的是防止攻击者执行并行攻击。必须从空间和时间两方面理解并行性;粗略地说,这意味着在两次或多次攻击之间分担攻击成本

    例如,考虑一个非盐化的哈希密码设置。攻击者可以按照与字典大小成比例的成本对字典中的所有单词进行散列,并根据几个散列密码检查这些散列单词。这可以是同步的(攻击者有一个哈希密码列表,并希望破解一个)或迭代的(攻击者预计算其哈希字典,然后将其用作针对不同系统中多个密码的工具)。不管怎样,这都是成本分担

    salt是一些数据,对于每个哈希密码实例,这些数据应该是唯一的。就盐的独特性而言,盐渍可以防止这种成本分摊

    将用户名(或其散列)用作salt可以利用用户名的唯一性:通常,在给定的系统上,在给定的时间,用户名是唯一的。这可以防止本地空间共享:如果攻击者获得所有散列密码的快照,他就无法与成本共享并行攻击它们;他将不得不为每一个被攻击的密码支付哈希字典费用。但是,这并不能阻止时间共享(攻击者预先计算一个哈希字典,其中salt对应于用户“bob”,并会定期尝试猜测bob的密码,假设bob定期更改其密码,例如,因为这是由其系统管理员强制执行的)。这并不能阻止某些全局共享(存在多个系统,其中一个用户的名字是“bob”)


    因此,使用用户名作为salt并不坏;这比完全不用盐要好。但随机salt更好,因为即使在用户名保持不变的情况下(一个用户更改密码;两个用户在不同的系统上使用相同的名称),随机salt也会发生变化。

    我将采取稍微相反的观点。基于给出的理由,纯粹的散列不是最好的主意(但总比没有好),但我认为如果你对应用程序范围的salt+用户名进行散列,情况就完全不同了。它仍然是每个用户的,但不是攻击者可以轻易猜到的。显然,您需要确保应用程序范围的salt对攻击者不可见,例如,通过从应用程序服务器目录树之外的文件读取它

    您可以使用多个哈希进一步扩展它。也就是说,不要只使用

      H(password.username.appsalt)
    
    用点什么
      H(password.username.appsalt)
    
      h1 = H(password.appsalt1.username.password)
      h2 = H(password.appsalt2.username.password)
      h3 = H(password.appsalt3.username.password)
      H(h1.H(h2.H(h3))))