在工作中,我们有两种相互竞争的盐理论。我工作的产品使用用户名或电话号码之类的东西来加盐。本质上,对于每个用户来说都是不同的,但我们很容易获得。另一款产品为每个用户随机生成一个salt,并在用户每次更改密码时更改。然后在数据库中加密盐。
我的问题是第二种方法是否真的有必要?我可以从纯理论的角度理解它比第一种方法更安全,但从实用性的角度来看呢?现在要对用户进行身份验证,salt 必须未加密并应用于登录信息。
在考虑之后,我只是没有看到这种方法真正的安全收益。将盐从一个帐户更改为另一个帐户,即使攻击者知道如何快速确定每个帐户的值,仍然使某人尝试暴力破解散列算法非常困难。这是在假设密码足够强的情况下进行的。 (显然,找到一组密码的正确哈希值,其中它们都是两位数字,比找到正确的 8 位密码哈希值要容易得多)。我的逻辑是不正确的,还是我遗漏了什么?
编辑:好的,这就是为什么我认为加密盐真的没有实际意义的原因。 (让我知道我是否走在正确的轨道上)。
对于下面的解释,我们假设密码总是 8 个字符,salt 是 5,所有密码都由小写字母组成(这只是为了让数学更容易)。
每个条目使用不同的盐意味着我不能使用相同的彩虹表(实际上,如果我有一个足够大的大小,我可以使用,但我们暂时忽略它)。据我了解,这是真正的关键,因为要破解每个帐户,我必须重新发明轮子,可以说每个帐户。现在,如果我知道如何将正确的盐应用于密码以生成散列,我会这样做,因为盐实际上只是扩展了散列短语的长度/复杂性。所以我会减少我需要生成的可能组合的数量,以“知道”我的密码+盐从 13^26 到 8^26,因为我知道盐是什么。现在这使它变得更容易,但仍然非常困难。
因此,对盐进行加密。如果我知道盐是加密的,我不会先尝试解密(假设我知道它有足够的加密级别)。我会忽略它。而不是试图弄清楚如何解密它,回到前面的例子,我只生成一个更大的彩虹表,其中包含 13^26 的所有密钥。不知道盐肯定会减慢我的速度,但我认为它不会增加尝试首先破解盐加密的艰巨任务。这就是为什么我认为这不值得。想法?
这是一个链接,描述了密码在暴力攻击下可以保存多长时间:http://www.lockdown.co.uk/?pg=combi
隐藏盐是不必要的。
每个哈希都应该使用不同的盐。在实践中,这很容易通过从加密质量随机数生成器中获取 8 个或更多字节来实现。
Salt有助于阻止预先计算的字典攻击。假设攻击者有一个可能的密码列表。他可以对每个哈希值进行哈希处理,并将其与受害者密码的哈希值进行比较,看看是否匹配。如果列表很大,这可能需要很长时间。他不想在下一个目标上花费太多时间,所以他将结果记录在一个“字典”中,其中哈希指向其相应的输入。如果密码列表非常非常长,他可以使用彩虹表之类的技术来节省一些空间。但是,假设他的下一个目标将他们的密码加盐。即使攻击者知道盐是什么,他的预计算表也毫无价值——盐会改变每个密码产生的哈希值。他必须重新散列他列表中的所有密码,将目标的盐添加到输入中。每种不同的盐都需要不同的字典,如果使用了足够多的盐,攻击者将没有空间为所有盐存储字典。交易空间以节省时间不再是一种选择;攻击者必须回退到对他想要攻击的每个目标的列表中的每个密码进行哈希处理。所以,没有必要对盐保密。确保攻击者没有与该特定盐对应的预先计算的字典就足够了。
在考虑了更多之后,我意识到欺骗自己认为可以隐藏盐是危险的。最好假设盐不能被隐藏,尽管如此,将系统设计为安全的。我提供更详细的解释in another answer.
然而,NIST 最近的建议鼓励使用额外的秘密“盐”(我看到其他人称这种额外的秘密“胡椒”)。可以使用这个秘密作为盐来执行密钥推导的另一个迭代。这一轮不是增加对预先计算的查找攻击的强度,而是防止密码猜测,就像一个好的密钥派生函数中的大量迭代一样。如果与散列密码一起存储,此机密将毫无用处;它必须作为秘密进行管理,这在大型用户数据库中可能很困难。
这里的答案是问问自己,你真正想要保护的是什么?如果有人可以访问您的数据库,那么他们就可以访问加密的盐,并且他们可能也可以访问您的代码。有了这些,他们可以解密加密的盐吗?如果是这样,那么无论如何加密几乎没有用。盐确实可以做到这一点,因此如果它被入侵,就不可能形成一个彩虹表来一次性破解您的整个密码数据库。从这个角度来看,只要每个盐都是唯一的,就没有区别,那么您的盐或每个密码的加密盐都需要进行暴力攻击。
我对“盐”的理解是它使破解更加困难,但它并没有试图隐藏额外的数据。如果您试图通过使盐“保密”来获得更高的安全性,那么您实际上只需要加密密钥中的更多位。
第二种方法只是稍微安全一点。盐可以保护用户免受字典攻击和彩虹表攻击。它们使雄心勃勃的攻击者更难破坏您的整个系统,但仍然容易受到针对您系统的一个用户的攻击。如果您使用公开可用的信息(例如电话号码),并且攻击者意识到了这一点,那么您已经为他们的攻击节省了一步。当然,如果攻击者获得了你的整个数据库、盐和所有东西,这个问题就没有实际意义了。
编辑:在重新阅读了这个答案和一些评论之后,我突然想到,一些混淆可能是由于我只比较了问题中提出的两个非常具体的案例:随机盐与随机盐。非随机盐。如果攻击者获取了您的整个数据库,那么使用电话号码作为盐的问题是没有实际意义的,而不是使用盐的问题。
...诸如用户名或电话号码之类的东西来加盐。 ...我的问题是第二种方法是否真的有必要?我可以从纯理论的角度理解它比第一种方法更安全,但是从实用性的角度来看呢?
从实际的角度来看,盐是一个实现细节。如果您改变了收集或维护用户信息的方式——使用您的确切示例,用户名和电话号码有时会发生变化——那么您可能已经损害了您的安全性。您是否希望这种面向外部的变化产生更深层次的安全问题?
停止要求每个帐户都有电话号码是否需要进行完整的安全审查,以确保您没有打开这些帐户导致安全漏洞?
这是一个简单的示例,说明为什么每个哈希使用相同的盐是不好的
考虑下表
UserId UserName, Password
1 Fred Hash1 = Sha(Salt1+Password1)
2 Ted Hash2 = Sha(Salt2+Password2)
情况 1 当 salt 1 与 salt2 相同 如果 Hash2 被 Hash1 替换,那么用户 2 可以使用用户 1 的密码登录
情况 2 当 salt 1 不一样 salt2 如果 Hash2 替换为 Hash1 则 user2 无法使用用户 1 的密码登录。
有两种技术,具有不同的目标:
“盐”用于使两个原本相等的密码以不同的方式加密。这样,入侵者就不能有效地使用字典攻击来攻击整个加密密码列表。
在散列消息之前添加(共享)“秘密”,因此入侵者无法创建自己的消息并让它们被接受。
我倾向于隐藏盐。我使用 10 位盐,方法是在对密码进行散列之前将 1 到 1024 的随机数添加到密码的开头。在将用户输入的密码与哈希值进行比较时,我从 1 循环到 1024 并尝试所有可能的 salt 值,直到找到匹配项。这需要不到 1/10 秒的时间。我从 PHP password_hash 和 password_verify 中得到了这样做的想法。在我的示例中,10 位盐的“成本”是 10。或者从另一个用户所说的,隐藏的“盐”被称为“胡椒”。盐在数据库中未加密。被强行逼出来了这将使彩虹表需要将散列反转 1000 倍。我使用 sha256 是因为它速度快,但仍然被认为是安全的。
实际上,这取决于您尝试保护数据的攻击类型。
每个密码的唯一盐的目的是防止对整个密码数据库的字典攻击。
为每个密码加密唯一的盐将使破解单个密码变得更加困难,是的,但您必须权衡是否真的有很多好处。如果攻击者通过蛮力发现这个字符串:
Marianne2ae85fb5d
哈希到存储在数据库中的哈希,真的很难弄清楚哪一部分是通行证,哪一部分是盐?