【发布时间】:2011-08-01 04:51:15
【问题描述】:
有人可以分享在 Python 中为 OAuth 请求创建随机数的最佳实践吗?
【问题讨论】:
标签: python authentication oauth nonce
有人可以分享在 Python 中为 OAuth 请求创建随机数的最佳实践吗?
【问题讨论】:
标签: python authentication oauth nonce
虽然这在创建此问题时可能不存在,但 Python 3.6 引入了 secrets 模块,该模块用于生成适合管理密码、帐户身份验证、安全令牌等数据的加密强随机数,以及相关的秘密。
在这种情况下,可以很容易地生成一个随机数(这里是一个base64编码的字符串):
nonce = secrets.token_urlsafe()
替代方法是 token_bytes 获取二进制令牌或 token_hex 获取十六进制字符串。
【讨论】:
nonce 是一个数字取决于令牌提供者如何实现它(严格来说,它不是 JWT 标准的一部分)。我见过的所有提供者都乐于使用字符串。重要的是它是一次性价值。只会增加的数字是好的,但您必须解决系统重置的问题。使用大的随机字符串通常更容易。
对于大多数实际目的,这提供了非常好的随机数:
import uuid
uuid.uuid4().hex
# 'b46290528cd949498ce4cc86ca854173'
uuid4() 使用os.urandom(),这是您可以在 python 中获得的最佳随机数。
Nonce 应该只使用一次并且难以预测。请注意,uuid4() 比 uuid1() 更难预测,而后者更具有全局唯一性。所以你可以通过结合它们来获得更大的力量:
uuid.uuid4().hex + uuid.uuid1().hex
# 'a6d68f4d81ec440fb3d5ef6416079305f7a44a0c9e9011e684e2c42c0319303d'
【讨论】:
python-oauth2 的做法如下:
def generate_nonce(length=8):
"""Generate pseudorandom number."""
return ''.join([str(random.randint(0, 9)) for i in range(length)])
他们还有:
@classmethod
def make_nonce(cls):
"""Generate pseudorandom number."""
return str(random.randint(0, 100000000))
另外还有一个题为:“make_nonce is not random enough”的issue,它提出:
def gen_nonce(length):
""" Generates a random string of bytes, base64 encoded """
if length < 1:
return ''
string=base64.b64encode(os.urandom(length),altchars=b'-_')
b64len=4*floor(length,3)
if length%3 == 1:
b64len+=2
elif length%3 == 2:
b64len+=3
return string[0:b64len].decode()
还引用了CVE-2013-4347。 TL;DR 版本,使用os.urandom 或它的抽象接口(@987654324@)。
我喜欢我的lambdas——并且不想要非字母数字字符——所以我使用了这个:
lambda length: filter(lambda s: s.isalpha(), b64encode(urandom(length * 2)))[:length]
【讨论】:
uuid1().get_hex()。不过,您可能想要uuid4 或uuid5,更多关于Python 符合的UUID 标准可以在RFC4122 中找到
os.urandom() 并且永远不要使用 random.random 或 random.randint。否则您可能会遇到严重的安全问题。
random.randint 很容易被坏人猜到,从而危及安全。 cigital.com/papers/download/developer_gambling.php
这就是rauth 的作用。这里没有真正的硬性规定。该规范似乎并不太自以为是。您的限制是,作为随机数的值应该是唯一的。除此之外,假设提供者没有抱怨,你可以使用任何你喜欢的方法。
【讨论】:
.encode('ascii'),然后将其提供给sha1。可能是为了兼容 Python 3?
以下是我对电子邮件的一些想法。 generate_nonce 来自他们的代码,但我使用了我使用 uuid 的 generate_nonce_timestamp。它给了我一个随机的字母数字字符串和一个以秒为单位的时间戳:
import random
import time
import uuid
def generate_nonce(length=8):
"""Generate pseudo-random number."""
return ''.join([str(random.randint(0, 9)) for i in range(length)])
def generate_timestamp():
"""Get seconds since epoch (UTC)."""
return str(int(time.time()))
def generate_nonce_timestamp():
"""Generate pseudo-random number and seconds since epoch (UTC)."""
nonce = uuid.uuid1()
oauth_timestamp, oauth_nonce = str(nonce.time), nonce.hex
return oauth_nonce, oauth_timestamp
我喜欢使用 uuid1,因为它会根据当前主机和时间生成 uuid,并且如果您需要两者都可以提取时间属性。对于电子邮件,您需要时间戳和随机数。
这是你得到的:
>>> generate_nonce_timestamp()
('a89faa84-6c35-11e5-8a36-080027c336f0', '136634341422770820')
如果要删除-,请使用nonce.get_hex()。
uuid1 - 根据主机 ID、序列号和当前时间生成 UUID。 更多关于uuid。
【讨论】:
random.randint 的评论(TL;DR:永远不会)