如何使用bcrypt比较明文密码和哈希密码?

40

我想使用bcrypt来加密密码,然后在以后验证提供的密码是否正确。

加密密码很容易:

import bcrypt

password = u'foobar'
password_hashed = bcrypt.hashpw(password, bcrypt.gensalt())

# then store password_hashed in a database

如何将明文密码与存储的哈希值进行比较?

6个回答

71

使用py-bcrypt,您无需单独存储salt: bcrypt会将salt存储在散列中。

您可以将散列直接用作salt,而salt存储在散列的开头。

>>> import bcrypt
>>> salt = bcrypt.gensalt()
>>> hashed = bcrypt.hashpw('secret', salt)
>>> hashed.find(salt)
0
>>> hashed == bcrypt.hashpw('secret', hashed)
True
>>>

8
回答不错,但是提醒一下,hash 是 Python 2 和 3 的保留关键词(内置函数),如果你设置 hash = ...,将会在你所在的作用域内覆盖内置函数。我建议把它改成像 hashedpw_hash 等其他名称。 - alichaudry
1
我同意。这个 hash 必须被替换为其他名称 :)。 - ivanleoncz
9
别忘了对字符串进行编码,'secret'.encode()。注:在 Python 3 中测试通过。 - Yamaneko

19

文档中没有提到存储盐,只需要执行以下操作:

#Initial generation
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
#Store hashed in your db

#Load hashed from the db and check the provided password
if bcrypt.hashpw(password, hashed) == hashed:
    print "It matches"
else:
    print "It does not match"

http://www.mindrot.org/projects/py-bcrypt/


每次调用bcrypt.gensalt()时都会生成一个新的盐,因此您必须将盐与bcrypt.hashpw()的结果一起保存。 - skyler
10
使用bcrypt时,盐值被存储为哈希的一部分。它被保存在哈希中,并且哈希会自动与其进行比较。 - Jonathan Vanasco
5
使用 == 比较哈希值会引入安全问题(时间攻击)。应该使用 hmac.compare_digest - rubik

6
稍后,假设您有一个用户输入的密码user_pass。您也会对其进行哈希处理,然后比较哈希值和存储的哈希值,如果它们匹配,则原始密码也匹配。

请注意,bcrypt自动将盐值作为加密密码的一部分进行存储,以便在将来对输入进行哈希时可以使用它。

第一次:

import bcrypt

password = u'foobar'
salt = bcrypt.gensalt()
password_hashed = bcrypt.hashpw(password, salt)

# store 'password_hashed' in a database of your choosing

后来的时代:

import bcrypt
password = something_that_gets_input()

stored_hash = something_that_gets_this_from_the_db()

if bcrypt.hashpw(password, stored_hash) == stored_hash:
    # password matches

谢谢!作为一个新手,我完全没有意识到盐和密码需要被存储并随后进行比较。非常感谢! - MFB
3
使用bcrypt时不需要存储盐值。下面的答案是正确的。 - Sharoon Thomas

6

我对Python不太熟悉,但我认为你可以使用以下方法:
public static boolean checkpw(java.lang.String plaintext, java.lang.String hashed)


该方法是用于检查哈希密码是否与明文密码匹配的公共静态布尔值。
# Check that an unencrypted password matches one that has  
# previously been hashed.
if bcrypt.checkpw(plaintext, hashed):
    print "It matches"
else:
    print "It does not match"

1
+1 为 checkpw(),但在生成或检查密码之前,请不要忘记使用 encode('utf-8') 或任何您在对明文进行哈希处理时使用的编码。 - SATYAJEET RANJAN

0

我认为这个会更好用:

for i in range(len(rserver.keys())):
    salt = bcrypt.gensalt(12)
    
    mdp_hash = rserver.get(rserver.keys()[i])
    rserver.set(rserver.keys()[i], bcrypt.hashpw(mdp_hash.encode(),bcrypt.gensalt(12) ))

    rsalt.set(rserver.keys()[i], salt)

0

首先从数据库中检索哈希密码。

hashed_pwd = ...
plain_text_pwd = 'my_password'
pwdbytes = plain_text_password.encode('utf-8)

假设您的密码以文本格式存储在数据库中,可以像这样进行比较:

if bcrypt.hashpw(pwdbytes, hashed_pwd.encode('utf-8')).decode('UTF-8') == hashed_pwd:
                print('Login successfull')

如果它以字节(blob)的形式存储,可以这样比较:

if bcrypt.hashpw(pwdbytes, hashed_pwd) == hashed_pwd:
                    print('Login successfull')

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