【问题标题】:What is the standard method for generating a nonce in Python?在 Python 中生成随机数的标准方法是什么?
【发布时间】:2011-08-01 04:51:15
【问题描述】:

有人可以分享在 Python 中为 OAuth 请求创建随机数的最佳实践吗?

【问题讨论】:

    标签: python authentication oauth nonce


    【解决方案1】:

    虽然这在创建此问题时可能不存在,但 Python 3.6 引入了 secrets 模块,该模块用于生成适合管理密码、帐户身份验证、安全令牌等数据的加密强随机数,以及相关的秘密。

    在这种情况下,可以很容易地生成一个随机数(这里是一个base64编码的字符串):

    nonce = secrets.token_urlsafe()
    

    替代方法是 token_bytes 获取二进制令牌或 token_hex 获取十六进制字符串。

    【讨论】:

    • 我最近听说了 nonce。根据我的理解,nonce 应该是整数类型,即数字。但是在这里,您尝试将 base64 编码的字符串作为随机数。所以nonce也可以是一个字符串
    • @SanthoshYedidi nonce 是一个数字取决于令牌提供者如何实现它(严格来说,它不是 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 或它的抽象接口(@98​​7654324@)。

    我喜欢我的lambdas——并且不想要非字母数字字符——所以我使用了这个:

    lambda length: filter(lambda s: s.isalpha(), b64encode(urandom(length * 2)))[:length]
    

    【讨论】:

    • 顺便说一句。 uuid1 根据主机和时间创建唯一密钥:import uuid; uuid.uuid1()。如果需要字母数字随机数,它可以转换为字符串并使用。它还有一个纪元 UTC 时间组件,即 uuid.uuid1().time 将返回一个长整数。
    • 要获取字符串,您也可以使用uuid1().get_hex()。不过,您可能想要uuid4uuid5,更多关于Python 符合的UUID 标准可以在RFC4122 中找到
    • 当然,除非您希望种子成为当前主机和时间,否则您可以使用 uuid1:docs.python.org/2/library/uuid.html。 get_hex() 很有用,谢谢!
    • 请注意,如果您尝试生成名称中带有“nonce”的任何内容,请务必使用 os.urandom() 并且永远不要使用 random.randomrandom.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:永远不会)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-17
    • 2012-02-05
    • 2015-06-10
    • 2016-12-16
    • 2011-01-09
    • 2011-12-09
    • 2010-10-12
    相关资源
    最近更新 更多