我试图对密码重置进行验证,我使用的是两个值:纪元时间,我想使用用户的旧密码(pbkdf2)作为关键,
由于我不想获得非ASCII字符,我已经使用SimpleEncode library,因为它只是一个使用密钥的BASE64,因为它很快,但问题是密码太长(196个字符)所以我得到一个长键!
我所做的是分割结果code = simpleencode.encode(key,asci)[::30]
,但这不是唯一的!
为了了解它是如何工作的,我已经尝试过Facebook重置过程,但给出的是一个数字!那么这个过程如何运作,他们不会使用密钥让某人难以伪造链接来重置某人的密码?
更新:算法将如何运作:
1-使用epoche获取时间time.time()
2-生成epoche时间的Base64(用于URL)和纪元时间值+一键,此键为PBKDF2(密码)。
3-生成网址www.example.com/reset/user/Base64(time.time())并发送此网址+ simpleencode.encode(key,asci)[::30]
答案 0 :(得分:30)
不确定这是最好的方法,但我可能只是生成一个UUID4,可以在URL中使用它来重置密码并在'n'时间后过期。
>>> import uuid
>>> uuid.uuid4().hex
'8c05904f0051419283d1024fc5ce1a59'
您可以使用类似http://redis.io的内容来保存该密钥,并使用相应用户ID的值并设置其生存时间。因此,当来自http://example.com/password-reset/8c05904f0051419283d1024fc5ce1a59的某些内容时,它会查看它是否有效,如果是,则允许更改设置新密码。
如果你确实想要一个“验证引脚”,那么就与令牌一起存储一个小的随机密钥,例如:
>>> from string import digits
>>> from random import choice
>>> ''.join(choice(digits) for i in xrange(4))
'2545'
请求在重置链接上输入。
答案 1 :(得分:18)
目前最简单的方法是使用ItsDangerous库:
您可以序列化并签署用户ID,以便将简报取消订阅到网址中。这样,您无需生成一次性令牌并将其存储在数据库中。对于帐户和类似事物的任何类型的激活链接都是一样的。
您还可以嵌入时间戳,因此可以非常轻松地设置时间段而无需涉及数据库或队列。它都是加密签名的,所以你可以很容易地看出它是否被篡改过。
>>> from itsdangerous import TimestampSigner
>>> s = TimestampSigner('secret-key')
>>> string = s.sign('foo')
>>> s.unsign(string, max_age=5)
Traceback (most recent call last):
...
itsdangerous.SignatureExpired: Signature age 15 > 5 seconds
答案 2 :(得分:1)
为什么不直接使用jwt作为token,它也可以设置一个过期时间,所以也可以给token设置一个过期日期。
为了生成 jwt 令牌,我使用 pyjwt
。下面的代码片段显示了如何在 24 小时(1 天)的到期时间完成并使用密钥签名:
import jwt
from datetime import datetime, timedelta, timezone
secret = "jwt_secret"
payload = {"exp": datetime.now(timezone.utc) + timedelta(days=1), "id": user_id}
token = jwt.encode(payload, secret, algorithm="HS256")
reset_token = token.decode("utf-8")
下面的代码片段展示了如何在 Django 中设置令牌验证和新密码。如果令牌已过期或被篡改,则会引发异常。
secret = "jwt_secret"
claims = jwt.decode(token, secret, options={"require_exp": True})
# Check if the user exists
user = User.objects.get(id=claims.get("id"))
user.set_password(password)
user.save()