我有两个休息端点,一个用于注册用户,另一个用于登录用户。这是我用来散列用户密码并将散列密码存储在数据库中的代码,
from passlib.hash import pbkdf2_sha256
def _get_hashed_password(self, password):
return pbkdf2_sha256.encrypt(password, rounds=200000, salt_size=16)
现在在登录端点上,我使用此代码验证散列密码
password = data['password']
hash = pbkdf2_sha256.encrypt(password, rounds=200000, salt_size=16)
pbkdf2_sha256.verify(user.hashed_password, hash)
这种方法失败并且很明显,因为两个密码不同,
$pbkdf2-sha256$200000$ai0FoDTG2BuDkDKGEIJQKg$Ik06dr61.2rRMDwZCZMdVq.zMe5887.ksDxvmSXFRwE
$pbkdf2-sha256$200000$pHTuHYNwLoXQeu8dI0QoxQ$2z4cZl9Njz9X/bxNtWCZzzeplWO.jTZA2v5lvcmgFE8
我想知道如何才能让它发挥作用?
答案 0 :(得分:5)
pbkdf2_sha256.encrypt
和pbkdf2_sha256.verify
不只是计算密码的哈希值。仔细查看pbkdf2_sha256.encrypt
$pbkdf2-sha256$200000$ai0FoDTG2BuDkDKGEIJQKg$Ik06dr61.2rRMDwZCZMdVq.zMe5887.ksDxvmSXFRwE
----------------------------------------------------------------------------------------
$ algorithm $rounds$ salt $ the actual hash
您可以在几年内切换算法,增加轮数,pbkdf2_sha256.verify
仍然可以根据数据库中存储的哈希验证明文密码。
两次使用相同的密码不会每次都给出相同的结果,因为使用了随机盐。如果攻击者获得密码哈希值,则盐会阻止rainbow table attacks。基本上,您不是仅计算hash(password)
,而是计算类似hash(salt + password)
的内容。由于盐已经在上面的字符串中给出,你可能知道密码,你也会知道salt + password
的价值,你的生活将不再困难。但对于花费大量时间预先计算hash(password)
的攻击者而言,这些哈希值都不会有用,因为它们不包含随机盐。
与评论中发布的示例一样,您无需执行任何特殊操作来验证密码:
pbkdf2_sha256.verify(password, user.hashed_password)
验证密码时无需拨打pbkdf2_sha256.encrypt
。 pbkdf2_sha256.verify
为您完成所有这些。