cem*_*ick 3 security authentication encryption cryptography
在构建我希望的是一个正确架构的身份验证机制的过程中,我遇到了很多指定的材料:
我完全同意第一点和第二点,但似乎后者有一个简单的解决方法.而不是做相当于(伪代码):
salt = random();
hashedPassword = hash(salt . password);
storeUserRecord(username, hashedPassword, salt);
Run Code Online (Sandbox Code Playgroud)
为什么不使用用户名的哈希作为盐?这产生了一个分布均匀(大致)随机的盐的区域,并且每个单独的盐与盐功能所提供的一样复杂.更好的是,您不必将salt存储在数据库中 - 只需在身份验证时重新生成它.更多伪代码:
salt = hash(username);
hashedPassword = hash(salt . password);
storeUserRecord(username, hashedPassword);
Run Code Online (Sandbox Code Playgroud)
(当然,hash
在上面的例子中应该是合理的,比如SHA-512,或者其他一些强哈希.)
这对我来说似乎是合理的,因为我知道加密的内容很少(但很少),但事实上这是对广泛推荐的练习的简化,这让我想知道是否有一些明显的原因让我误入歧途,我不知道.
编辑有些人似乎没有意识到问题是什么.我无法建议不使用盐.参考TheRook的编辑答案:我熟悉那些CWE中提到的参考文献.我的核心问题是:为什么hash(用户名)是可预测的盐?
编辑2感谢所有提供答案的人; biffabacon在他的第2段直接解决了我的核心问题(基本上,你可以做的任何事情,以最大限度地使用盐的域,因此生成的哈希密码是好的),但在这个问题的各种评论中有很多美味的信息.
盐的原因是为了防止密码分析攻击.每个用户的唯一盐意味着您无法判断两个用户是否具有相同的密码.每个用户的非确定性盐意味着您无法判断两个系统上是否使用了相同的用户名:密码.
不要试图改变盐.如果你不喜欢这个空间,那么就不要使用它们,并努力直接保护你的数据(和备份!).
盐有助于使用预计算或字典攻击防御攻击者.使用salt时,攻击者需要为每个salt值创建一个单独的字典.但是,如果盐不是随机的,则会给攻击者一个优势,因为他们可以创建比其他人更可能的词典.例如,他们可以使用jsmith的盐(或jsmith的哈希)创建一个字典.出于这个原因,盐通常是随机的好主意.
比较对哈希(用户名)盐和随机盐预计算攻击:让我们说,例如攻击者决定为最常见的1000名的用户名和,比如说,半打不同的散列的ALG创建词典; 这是6000盐和6000字典.如果使用随机32位盐,则为2 ^ 32或大约42亿个字典.因此,当盐空间显着减少时(就像使用哈希(用户名)一样),预先计算的攻击变得更加可行
盐的目的是防止攻击者进行并行攻击.必须在空间和时间上理解这种并行性; 粗略地说,这意味着在两次或更多次攻击之间共享攻击成本.
例如,考虑一个非盐渍哈希密码设置.攻击者可以散列字典中的所有单词,其成本与字典的大小成比例,并检查那些散列的单词是否与几个散列密码有关.这可以是同时的(攻击者有一个散列密码列表并希望破解一个)或迭代(攻击者预先计算他的散列字典,然后将其用作针对不同系统中的几个密码的工具).无论哪种方式,这都是成本分摊.
的盐是一些数据应该有点唯一的每个哈希密码实例.盐析可以防止这种成本分担,达到盐的独特程度.
使用用户名(或其散列)作为salt利用用户名唯一性:通常,在给定时间的给定系统上,用户名是唯一的.这可以防止本地空间共享:如果攻击者获得所有哈希密码的快照,他就无法与成本共享并行攻击它们; 他将不得不为每个受攻击的密码产生哈希字典费用.但是,这并不妨碍时间共享(攻击者使用对应于用户"bob"的盐预先计算散列字典,并且会定期尝试猜测Bob的密码,假设Bob定期更改其密码,例如因为这是由他的系统管理员强制执行).这并不能阻止某些全局共享(有几个 - 很多 - 系统在那里,用户名称为"bob").
所以使用用户名作为盐也不错; 这比不使用盐更好.但随机盐仍然更好,因为即使在用户名保持不变的情况下(用户更改其密码;具有相同名称的不同系统上的两个用户),它也会发生变化.