简体   繁体   English

在python中生成重置令牌的最佳方法是什么?

[英]what is the best way to generate a reset token in python?

I'm trying to make a validation process for a password reset, what i've used are two values: the epoch time, and i want to use the users's old password (pbkdf2) as a key,我正在尝试为密码重置进行验证过程,我使用的是两个值:纪元时间,我想使用用户的旧密码 (pbkdf2) 作为密钥,

Since i dont want to get non ASCII characters, i've used SimpleEncode library because it's fast since it's only a BASE64 with a key used, but the problem is that the password is too long (196 chars) so i get a long key!因为我不想得到非 ASCII 字符,所以我使用了SimpleEncode 库,因为它很快,因为它只是一个使用密钥的 BASE64,但问题是密码太长(196 个字符)所以我得到了一个长密钥!

What i've done is split the result code = simpleencode.encode(key,asci)[::30] , but this will not be unique!我所做的是拆分结果code = simpleencode.encode(key,asci)[::30] ,但这不会是唯一的!

To get an idea how it works, i've tried Facebook reset process, but what is given is a number!为了了解它是如何工作的,我尝试了 Facebook 重置过程,但给出的是一个数字! so how this process works, don't they use a key to make it hard for someone to forge a link to reset someone's password?那么这个过程是如何工作的,他们不是使用密钥来使某人难以伪造链接来重置某人的密码吗?

Update: how the algorithme will work:更新:算法将如何工作:

1- get the time using epoche time.time() 1- 使用 epoch time.time()获取时间

2- generate the Base64 of the epoche time (to use for the URL) and the epoch time value + a key, this key is PBKDF2(password). 2-生成纪元时间的Base64(用于URL)和纪元时间值+一个密钥,这个密钥是PBKDF2(密码)。

3- generate the url www.example.com/reset/user/Base64(time.time()) and send this URL + the simpleencode.encode(key,asci)[::30] 3- 生成网址 www.example.com/reset/user/Base64(time.time()) 并发送此网址 + simpleencode.encode(key,asci)[::30]

4- when the user clicks on the URL, he put the generated code, this generated code, if it matches with the URL, then let him modifiy the password, else, it is a forget URL! 4-当用户点击URL时,他把生成的代码,这个生成的代码,如果与URL匹配,则让他修改密码,否则,它是一个忘记URL!

Not sure it's the best way, but I'd probably just generate a UUID4, which can be used in a URL to reset the password and expire it after 'n' amount of time.不确定这是最好的方法,但我可能只是生成一个 UUID4,可以在 URL 中使用它来重置密码并在“n”个时间后过期。

>>> import uuid
>>> uuid.uuid4().hex
'8c05904f0051419283d1024fc5ce1a59'

You could use something like http://redis.io to hold that key, with a value of the appropriate user ID and set its time to live.您可以使用诸如http://redis.io 之类的东西来保存该密钥,并使用相应用户 ID 的值并设置其生存时间。 So, when something comes in from http://example.com/password-reset/8c05904f0051419283d1024fc5ce1a59 it looks to see if it's valid and if so then allows changes to set a new password.因此,当某些内容来自http://example.com/password-reset/8c05904f0051419283d1024fc5ce1a59 时,它会查看它是否有效,如果有效,则允许更改以设置新密码。

If you did want a "validation pin", then store along with the token, a small random key, eg:如果您确实想要一个“验证引脚”,那么与令牌一起存储一个小的随机密钥,例如:

>>> from string import digits
>>> from random import choice
>>> ''.join(choice(digits) for i in xrange(4))
'2545'

And request that be entered on the reset link.并要求在重置链接上输入。

Easiest way by far is to use the ItsDangerous library:到目前为止,最简单的方法是使用ItsDangerous库:

You can serialize and sign a user ID for unsubscribing of newsletters into URLs.您可以序列化用户 ID 并对其进行签名,以将时事通讯取消订阅到 URL 中。 This way you don't need to generate one-time tokens and store them in the database.这样您就不需要生成一次性令牌并将它们存储在数据库中。 Same thing with any kind of activation link for accounts and similar things.任何类型的帐户激活链接和类似的东西都是一样的。

You can also embed a timestamp, so very easily to set time periods without having to involve databases or queues.您还可以嵌入时间戳,因此无需涉及数据库或队列即可轻松设置时间段。 It's all cryptographically signed, so you can easily see if it's been tampered with.它都是经过加密签名的,因此您可以轻松查看它是否被篡改。

>>> 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

Why not just use a jwt as token for this purpose, its also possible to set an expiration time to it, so its also possible to put an expiration date to the token.为什么不为此目的仅使用 jwt 作为令牌,也可以为其设置过期时间,因此也可以为令牌设置过期日期。

  1. Generate token(JWT) encrypted with a secret key生成用密钥加密的令牌(JWT)
  2. Send mail containg a link with the token as a query paramater(When the user opens the link the page can read the token)发送包含以令牌为查询参数的链接的邮件(当用户打开链接时,页面可以读取令牌)
  3. Verify the token before saving the new password在保存新密码之前验证令牌

For generating jwt tokens I use pyjwt .为了生成 jwt 令牌,我使用pyjwt The below code snippet shows how it can be done with an expiry time of 24 hours(1 day) and signed with a secret key:下面的代码片段显示了如何在 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")

Below snippet shows how the verification of token and the new password can be set in django.下面的代码片段显示了如何在 Django 中设置令牌验证和新密码。 If the token has expired or has been tampered with, it will raise an exception.如果令牌已过期或已被篡改,则会引发异常。

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM