你如何向现有的密码哈希值中添加盐?

12

我有一个未添加盐值就被哈希的密码数据库。我想给新密码添加盐值。显然,无法在现有的密码上重新进行哈希处理。

您会如何迁移到新的哈希系统?


你实际上是在对密码进行哈希,还是使用了更复杂的方法?由于编码错误,我也遇到了类似的问题 - 但原始代码实际上是对“1”+登录名+密码进行哈希 - 这已经足够复杂,使得彩虹表攻击变得相当困难(特别是因为登录名不是用户选择的)。 - Eamon Nerbonne
我直接对密码进行了哈希处理。看起来你已经添加了盐。你的方法很好,因为除了盐之外,相同的密码不会有相同的哈希值,因为你还添加了登录名。 - Brandon O'Rourke
8个回答

32
当然可以。只需向现有哈希添加一个盐并再次哈希即可。当然,这将需要任何未来的登录都通过相同的过程,意味着需要调用两个哈希函数,但许多合法的模式已经这样做了,所以它不会像你想象的那样糟糕。
对密码进行加盐是为了防止彩虹表攻击。在这种情况下,盐不需要保密。
你可以在文章中看到:http://en.wikipedia.org/wiki/Rainbow_tables#Defense_against_rainbow_tables
hash = MD5 (MD5 (password) . salt)

这是完全相同的方法,除了使用了不同的哈希函数。


有趣的想法。不过你确定这样做不会在某种程度上影响安全性吗?特别是这样一来,一个人在获取第二个哈希后的字符串时,将会获得关于前一步骤的大量信息(例如常数长度),这可能会帮助他找到盐。 - Sinan Taifour
3
盐并不是秘密。事实上,您需要将它们(以明文形式)与每个用户一起保存。 - Spencer Ruport
当我正在回答这个问题并说“你不能这样做”时,我读到了你聪明的解决方案。干得好 +1 - Graeme Perrow

14

作为一个快速解决方案,您可以在数据库中创建一个salt列,在用户正确匹配旧哈希值时,您可以使用他们输入的密码和salt创建一个新的哈希值。


这也是我的方法。 重构绝对不仅限于代码,还需要在数据库层面上进行,实际上必须这样做。 - Joseph Ferris
1
这个问题在于假设用户最终会登录,而这并不一定成立。同时,他们的密码更容易遭受攻击。如果再加上人们经常重复使用用户名和密码的事实……你应该选择Spencer的解决方案。 - Flory
我认为这非常不安全,因为这意味着您将明文密码发送到服务器。为了防止中间人攻击,您应该将哈希后的密码发送到服务器。 - Kolky

2
您可以添加一列,其中包含一个标志,显示用户是否具有旧(无盐)或新(带盐)哈希。
一个好主意是,在此时强制所有用户在登录时更改密码。这样您最终可以摆脱该列。

或者将列设置为hash_type(nosalt,md5,sha1,sha512)。如果是“nosalt”,则执行一项操作;如果是其他,则使用行中存储的盐列进行比较,并在升级时使用相应的哈希函数(因为MD5已经变得更弱)。 - Alister Bulman

1

我曾经处理过一个涉及多种哈希技术的类似问题。我采用了在数据库中编码哈希方法类型的方法(例如“alpha”,“beta”,“gamma”,“delta”)。我标记了所有当前哈希值的适当级别。当用户登录时,我验证他们的密码并使用更新后的方法重新哈希它们。我们的密码在90天后过期,所以只需要坚持3个月,直到所有使用旧方法的密码都可以重置。


0

我存储盐的最佳方式是将盐值嵌入到我刚创建的密码哈希+盐中。我不会将盐字符串附加到哈希的开头或结尾,而是将盐直接嵌入到哈希中。


盐不是应该这样使用吗?为了确保我没有误解您的意思,您是指hash(salt + password)吗? - Gary

0

这里有一些方法可能适用于您。
记住,任何添加到现有哈希中的恒定模式都是无用的(该链接上的一个技巧建议采用此类方法)。不应存在可用于隔离盐的可识别模式。

当然,最好的方法是迁移到加盐哈希表。


0
在你的数据库中创建一个名为“salted”的新字段,并将其类型设置为true/false(或与您的DBMS相同的等效类型)。将现有哈希值的所有值都设置为false。每当添加一个新的、加盐过的哈希时,就将“salted”字段设置为true。
然后,在代码中只需要处理两种类型的哈希即可。
这更像是一个通用解决方案而不是具体的解决方案,但它应该可以解决您的问题。

0
如果您将盐存储在哈希内部,那么通过检查哈希的长度就可以很容易地确定是否包含盐。如果没有盐,只需对密码进行哈希,如果有盐,则对密码+盐进行哈希。
您不需要在数据库中使用布尔列。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接