我有传统的浏览器游戏,历史上使用简单的哈希函数进行密码存储。我知道它'远非理想。然而,时间已经证明,大多数作弊者(多帐户)对所有虚假账户使用相同的密码。
在更新我的游戏时,我想更安全地存储密码。我已经知道,密码应该随机加盐,通过安全算法等进行散列。这一切都很好。
但有没有办法,如何正确存储密码并确定两个(或更多)用户使用相同的密码?我不想知道密码。我不希望能够通过密码进行搜索。我只需要说,可疑用户A,B和C使用同一个。
感谢。
答案 0 :(得分:0)
如果你正确存放它们 - 没有。这是正确密码存储的要点之一。
你可以拥有非常长的密码,超出了彩虹桌上可用的密码(不确定当前的技术状态,但它曾经是10或12个字符)而不是盐。在这种情况下,两个密码将具有相同的哈希值。 这是一个非常糟糕的主意(但仍然是一个解决方案) - 如果您的密码泄露,可能有人间接猜测它们(xkcd参考)。
您也可以查看homomorphic encryption,但现在这是科幻小说的范畴。
答案 1 :(得分:0)
好吧,如果你使用salt + hashing,那么所有的盐都是纯文本。当用户输入密码时,在存储/验证密码之前,您可以使用所有可用的盐对其进行哈希处理,并查看是否获得了相应的现有哈希值。 :)
这个问题的一个明显问题是,如果你使用bcrypt或pbkdf2正确地进行散列,那么这将非常慢 - 这就是这些函数中的重点。
我认为没有任何其他方法可以判断两个密码是否相同 - 您至少需要其中一个纯文本,这仅在用户输入时才显示。然后你想要从内存中删除它,这与使用内存中的纯文本密码进行所有这些计算相矛盾。
答案 2 :(得分:0)
这会在一定程度上降低所有密码的安全性,因为它会泄漏有关两个用户何时拥有相同密码的信息。即便如此,这是一个可行的权衡,并且可以直接确保在该限制范围内。
简短的回答是:对所有密码使用相同的盐,但为您的网站制作独特的盐。
现在答案很长:
首先,描述处理密码的标准和适当方式。之后我会找到你的不同之处。 (你可能已经知道所有这些,但值得重申。)
从一个不错的密钥拉伸算法开始,例如PBKDF2(还有其他的,有些甚至更好,但PBKDF2无处不在,足以满足大多数用途)。根据涉及的客户端环境选择多个迭代次数。对于JavaScript,您需要1k-4k迭代之类的东西。对于数学速度更快的语言,您可以使用10k-100k。
关键担架需要盐。我马上谈论盐。
客户端将密码发送到服务器。服务器应用快速哈希(SHA-256很好)并将其与存储的哈希进行比较。 (为了设置密码,服务器执行相同的操作;它接受PBKDF2哈希,应用SHA-256,然后存储它。)
所有这些都是标准的东西。问题是盐。最好的盐是随机的,但对此没有好处。第二好的salt是从service_id + user_id构建的(即使用服务的唯一标识符并连接用户名)。这两者都确保每个用户的密码哈希都是唯一的,即使他们的密码是相同的。但你不想要那个。
所以现在终于到了问题的核心。您希望使用每个服务,但不是每个用户,静态盐。所以像" com.example.mygreatapp" (显然不要使用该实际字符串;请根据您的应用使用字符串)。使用恒定的salt,服务上相同的所有密码都将拉伸(PBKDF2)和散列(SHA256)为相同的值,您可以比较它们,而不知道实际的密码是什么。但是,如果您的密码数据库被盗,攻击者无法将其中的哈希值与其他站点中的哈希值进行比较。数据库,即使他们使用相同的算法(因为他们会有不同的盐)。
此方案的缺点正是其目标:如果您网站上的两个人拥有相同的密码,攻击者窃取您的数据库并知道一个用户的密码,他们也知道另一个用户的密码。这是一种权衡。