werkzeug的`generate_password_hash`输出为什么不是常量?

33
当我多次运行werkzeug.security.generate_password_hash("Same password") (docs)时,每次的输出都不同。
我做错了什么?为什么它不是恒定的?

2
结果发现我在存储到数据库时截断了它。因此,我无法正确比较它 :-) - Shankar ARUL
2
谢谢您提出这个问题 - 我本来是要重新计算才能进行比较,而不是使用 check_password_hash() 方法。如果没有看到问题的答案,我就不会知道该怎么做了。感谢两位的回答。 - JakeJ
1个回答

75

密码是加盐的。在进行哈希之前,将盐添加到密码中,以确保哈希无法用于彩虹表攻击

由于每次调用函数时都会随机生成盐,因此生成的密码哈希值也不同。返回的哈希值包括生成的盐,以便能够正确验证密码。

演示:

>>> from werkzeug.security import generate_password_hash
>>> generate_password_hash('foobar')
'pbkdf2:sha1:1000$tYqN0VeL$2ee2568465fa30c1e6680196f8bb9eb0d2ca072d'
>>> generate_password_hash('foobar')
'pbkdf2:sha1:1000$XHj5nlLU$bb9a81bc54e7d6e11d9ab212cd143e768ea6225d'

这两个字符串不同,但包含足够的信息来验证密码,因为生成的盐被包含在每个字符串中:

# pbkdf2:sha1:1000$tYqN0VeL$2ee2568465fa30c1e6680196f8bb9eb0d2ca072d
  ^^^^^^^^^^^^^^^^   salt   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      algo info    ^^^^^^^^        actual hash of the password
  (PBKDF2 applied SHA1 1000 times)
因为随机盐对于其中一个是tYqN0VeL,而对于另一个是XHj5nlLU,所以生成的哈希值也不同。 foobar密码仍然可以验证任一哈希值:
>>> from werkzeug.security import check_password_hash
>>> check_password_hash('pbkdf2:sha1:1000$tYqN0VeL$2ee2568465fa30c1e6680196f8bb9eb0d2ca072d', 'foobar')
True
>>> check_password_hash('pbkdf2:sha1:1000$XHj5nlLU$bb9a81bc54e7d6e11d9ab212cd143e768ea6225d', 'foobar')
True

另请参见


1
那么,如果盐在生成的哈希中可见——难道不比以某种方式秘密存储盐更不安全吗? - Элёржон Кимсанов
3
@ЭлёржонКимсанов:盐的作用是为了防止彩虹表攻击,这是一种将常见密码转换为哈希值的列表。如果没有随机盐,这样的表格就很容易提前生成,然后反复使用。有了盐,您需要生成与可能的盐值一样多的表格,这根本不可行。盐值本身并不重要,只要同一数据库中的不同密码使用不同的随机盐值即可。因此,盐可见并不会造成安全风险,只有没有适当的随机盐值才会造成风险。 - Martijn Pieters

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