在 Python 中生成随机数的标准方法是啥?
Posted
技术标签:
【中文标题】在 Python 中生成随机数的标准方法是啥?【英文标题】:What is the standard method for generating a nonce in Python?在 Python 中生成随机数的标准方法是什么? 【发布时间】:2011-08-01 04:51:15 【问题描述】:有人可以分享在 Python 中为 OAuth 请求创建随机数的最佳实践吗?
【问题讨论】:
【参考方案1】:虽然这在创建此问题时可能不存在,但 Python 3.6 引入了 secrets 模块,该模块用于生成适合管理密码、帐户身份验证、安全令牌等数据的加密强随机数,以及相关的秘密。
在这种情况下,可以很容易地生成一个随机数(这里是一个base64编码的字符串):
nonce = secrets.token_urlsafe()
替代方法是 token_bytes 获取二进制令牌或 token_hex 获取十六进制字符串。
【讨论】:
我最近听说了 nonce。根据我的理解,nonce 应该是整数类型,即数字。但是在这里,您尝试将 base64 编码的字符串作为随机数。所以nonce也可以是一个字符串 @SanthoshYedidinonce
是一个数字取决于令牌提供者如何实现它(严格来说,它不是 JWT 标准的一部分)。我见过的所有提供者都乐于使用字符串。重要的是它是一次性价值。只会增加的数字是好的,但您必须解决系统重置的问题。使用大的随机字符串通常更容易。
是的,没错,增量很难跟踪【参考方案2】:
对于大多数实际目的,这提供了非常好的随机数:
import uuid
uuid.uuid4().hex
# 'b46290528cd949498ce4cc86ca854173'
uuid4()
使用os.urandom()
,这是您可以在 python 中获得的最佳随机数。
Nonce 应该只使用一次并且难以预测。请注意,uuid4()
比 uuid1()
更难预测,而后者更具有全局唯一性。所以你可以通过结合它们来获得更大的力量:
uuid.uuid4().hex + uuid.uuid1().hex
# 'a6d68f4d81ec440fb3d5ef6416079305f7a44a0c9e9011e684e2c42c0319303d'
【讨论】:
如果您假设 uuid1() 由于基于 MAC 地址而更具全局唯一性,那么您应该知道 MAC 地址在实践中远非唯一。一些制造商对给定的批次/型号使用相同的 MAC 地址......因此,基于该假设,您的陈述是错误的。恰恰相反。 @comte 不仅如此。 UUID1 还包含时间戳。只要世界上某些计算机具有不同的 MAC-s,MAC 就会增加一定程度的独特性。 source【参考方案3】: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@)。
我喜欢我的lambda
s——并且不想要非字母数字字符——所以我使用了这个:
lambda length: filter(lambda s: s.isalpha(), b64encode(urandom(length * 2)))[:length]
【讨论】:
顺便说一句。 uuid1 根据主机和时间创建唯一密钥:import uuid; uuid.uuid1()。如果需要字母数字随机数,它可以转换为字符串并使用。它还有一个纪元 UTC 时间组件,即 uuid.uuid1().time 将返回一个长整数。 要获取字符串,您也可以使用uuid1().get_hex()
。不过,您可能想要uuid4
或uuid5
,更多关于Python 符合的UUID 标准可以在RFC4122 中找到
当然,除非您希望种子成为当前主机和时间,否则您可以使用 uuid1:docs.python.org/2/library/uuid.html。 get_hex() 很有用,谢谢!
请注意,如果您尝试生成名称中带有“nonce”的任何内容,请务必使用 os.urandom()
并且永远不要使用 random.random
或 random.randint
。否则您可能会遇到严重的安全问题。
"nonce" 是密码学家发明的一个词,它需要一个新词来明确表示“没人能猜到的值”(实际上,一个足够大的密码安全随机整数)。他们在他们的协议中以许多创造性的方式使用它们,并且总是假设没有人能猜到它们。 random.randint
很容易被坏人猜到,从而危及安全。 cigital.com/papers/download/developer_gambling.php【参考方案4】:
这就是rauth 的作用。这里没有真正的硬性规定。该规范似乎并不太自以为是。您的限制是,作为随机数的值应该是唯一的。除此之外,假设提供者没有抱怨,你可以使用任何你喜欢的方法。
【讨论】:
请注意,它现在还调用.encode('ascii')
,然后将其提供给sha1
。可能是为了兼容 Python 3?【参考方案5】:
以下是我对电子邮件的一些想法。 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。
【讨论】:
查看我对 @AT 关于 nonces 和random.randint
的评论(TL;DR:永远不会)以上是关于在 Python 中生成随机数的标准方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 Python 3 中生成具有随机长度的类随机唯一字符串的最快方法