我正在通过Miguel Grinberg的出色教程来学习Flask。在该章中,出于安全原因,他建议存储用户的密码哈希而不是密码本身。使用的功能是generate_password_hash
,check_password_hash
。但是,即使您使用相同的字符串调用generate_password_hash
,也可以获得不同的哈希值:
如果同一字符串可以具有任意多的哈希值,那么check_password_hash
怎么工作?
答案 0 :(得分:4)
密码用盐打乱,盐是字母和数字的伪随机字符串。每次您运行generate_password_hash()
时,盐值都会有所不同。因此,产生的哈希也将有所不同。
这样做是为了使黑客无法简单地猜测常用密码的哈希值。例如,“ pass1234”本身的哈希值每次都会相同。但是,“ pass1234 + salt”的哈希值每次都不同。您的数据库应存储哈希值和盐值(重要的不是明文密码)。这样可以最大程度地减少如果泄露有关用户帐户的信息所造成的损害。
对于Flask和werkzeug,generate_password_hash()
的返回值的格式为:method$salt$hash
(您可以在提供的屏幕快照中看到两个$
符号)。因此,下次您针对哈希检查纯文本密码时,将其与generate_password_hash()
中的salt值一起使用,并查看其是否与哈希值匹配。
答案 1 :(得分:1)
然后,如果相同的字符串可以具有尽可能多的>哈希值,那么check_password_hash如何工作?
一个简化的解决方案可能是这样的,
user_id| raw_password | hash_value
user1 | 'foo' | same_hashed_value
user2 | 'foo' | same_hashed_value
您可能已经知道,这里相同的密码会产生相同的哈希值,
容易受到字典攻击。所以我们可以添加一些随机值(salt
)到
减轻这种攻击,如以下解决方案所示。
生成哈希过程:
user_id | raw_password | password_with_salt | hash_value
user1 | 'foo' | 'foo#salt123' | different_hash_1
user2 | 'foo' | 'foo#saltABC' | different_hash_2
在这种情况下,hash_value及其相关的salt_value可以存储在数据库中。否则,将concat(hash_vaule
,salt_value
)作为要存储的一个字符串,等效。
检查哈希过程:
1)从数据库中检索用户的salt_value和hash_value。
2)将salt_value附加到给定的密码,并使用相同的哈希函数对其进行哈希。
3)将给定密码的哈希值与数据库中的哈希值进行比较。如果它们匹配,则密码正确。否则,密码不正确。