我生成一个由单个使用令牌组成的URL,并通过电子邮件将其发送给用户。用户应单击此链接并重定向到将验证令牌并执行某些操作的页面。
在数据库方面,我存储此令牌(出于安全原因,哈希和盐渍)。问题是我在验证令牌方面遇到了一些困难,因为我存储它的方式,我不能为同一令牌生成相同的盐。因此,我无法将这种盐与我储存的盐进行比较。
# Retrieving or creating object usertokens
usr, created = UserToken.objects.get_or_create(email=email)
# Adding a new token
token = uuid.uuid4().hex
usr.token = make_password(token) # Stores in the local database the salted and hashed token
usr.save()
我使用的make_password方法在django.contrib.auth.hashers
中定义。
通过使用此方法,我无法从同一令牌生成两次相同的盐。
>>> token = 'test'
>>> enc_token1 = make_password(token)
>>> enc_token2 = make_password(token)
>>> enc_token1 == enc_token2
False
然而,这并没有帮助我从我的数据库中检索对应于令牌的条目,我无法验证它。
答案 0 :(得分:1)
使用两个散列和盐渍标记的简单字符串相等检查将不起作用。 Django docs for password management在django.contrib.auth.hashers
命名空间中提供了一个非常简单的方法,可以为您处理所有这些:
>>> token = 'test'
>>> enc_token1 = make_password(token)
>>> check_password('test', enc_token1)
True
check_password
方法做了一些事情,比如检查哈希算法是否已经改变。它返回实现verify
基类的算法的BasePasswordHasher
方法的结果。以下是source of the PBKDF2PasswordHasher
:
def verify(self, password, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == self.algorithm
encoded_2 = self.encode(password, salt, int(iterations))
return constant_time_compare(encoded, encoded_2)
注意如何通过在' $'上分割encoded_string来找到salt,因为Django docs note
User对象的password属性是这种格式的字符串:
<algorithm>$<iterations>$<salt>$<hash>