【问题标题】:How to generate a unique auth token in python?如何在 python 中生成唯一的身份验证令牌?
【发布时间】:2017-05-12 06:34:13
【问题描述】:

我正在尝试在烧瓶中为我的 android 应用程序编写一个基于令牌的身份验证。为此,我需要一个唯一的令牌,我可以使用它来验证用户。

Itsdangerous 库提供了一个 JSONWebSignatureSerializer 函数,我可以使用它创建 JWT 令牌。所以我的第一个问题是,使用 JWT 进行基于移动的身份验证是否安全?

其次,我对 django rest 框架如何生成它的令牌做了一点研究。

def generate_key(self):
    return binascii.hexlify(os.urandom(20)).decode()  

这个令牌是唯一的还是只是一个随机的?对于基于移动设备的身份验证,我应该使用哪一个?

在python中为移动应用程序生成唯一令牌的基础方法是什么?

【问题讨论】:

  • 与其重新发明轮子(通常不是一个好主意,尤其是在安全方面),为什么不使用像flask-jwt 这样的解决方案?

标签: python django python-3.x flask


【解决方案1】:

您可以像提到的那样使用内置的uuid 模块。 3.6 中发布的新secrets 模块也能够创建唯一令牌。

from uuid import uuid4

rand_token = uuid4()

下面的函数在每次调用时都会创建一个唯一的令牌。 os.urandom 方法返回 20 个随机字节作为字符串,binascii.hexlify 方法将这 20 个字节中的每一个转换为该字节的 2 位十六进制表示。这就是为什么返回值是两倍长的原因。

如果您想使用这种方法并且需要特定长度的标记,请使用您所需长度的 一半 作为 os.urandom 方法的参数。

def generate_key(self):
    return binascii.hexlify(os.urandom(20)).decode()

【讨论】:

    【解决方案2】:

    好的,这是旧的,但我还是要插话。您需要决定:您想要独特的还是随机的?选择一个。

    如果您想要唯一,请使用 UUID。 UUID 的全部目的是确保您生成独特的东西。 UUID 代表通用唯一 ID。

    如果您想要随机的东西,请使用os.urandom。真正的随机结果不能局限于唯一性约束!那会让它们不是随机的。实际上,它会使它们成为 UUID。

    现在,对于您的问题,您需要一个身份验证令牌。这意味着您将其用于安全目的。 UUID 是错误的解决方案,而生成安全号码是正确的解决方案。生成随机数而不是 UUID 时会发生冲突吗?是的。但除非您拥有大量用户,否则这不太可能。您需要对此进行数学计算,但我的建议是:当您打算使用随机时,不要使用 UUID。

    哦。

    【讨论】:

    • UUID4 有一个随机生成的部分。还要考虑到:生成重复 UUID 的概率不为零!但它足够小,可以被认为是独一无二的。
    【解决方案3】:

    查看 uuid() 库。文档在这里:

    https://docs.python.org/2/library/uuid.html

    之前对该问题的讨论在这里:

    How to create a GUID/UUID in Python

    有很多很好的细节。

    【讨论】:

    • 我已经研究过了,但是包括 django、pyramid 在内的 python 框架都没有使用 UUID 生成令牌。他们正在使用 binascii.hexlify(os.urandom(20)).decode()
    • 这个讨论有用吗? Django 内置了 uuid。stackoverflow.com/questions/3936182/…
    【解决方案4】:

    我写了一个小助手函数,用于在 django 模型中生成唯一标记。您可以从模型的 save() 方法调用它。它使用定义的函数生成候选标记,在数据库中的现有行中搜索该候选标记。如果找到,它会再试一次,否则,它会返回候选字符串。请注意,这里有一个小的竞争条件,但不太可能发生在具有足够大范围输出的令牌函数中。

    def generate_unique_token(Model,
                          token_field="token",
                          token_function=lambda: uuid.uuid4().hex[:8]):
    """
    Generates random tokens until a unique one is found
    :param Model: a Model class that should be searched
    :param token_field: a string with the name of the token field to search in the model_class
    :param token_function: a callable that returns a candidate value
    :return: the unique candidate token
    """
    unique_token_found = False
    while not unique_token_found:
        token = token_function()
        # This weird looking construction is a way to pass a value to a field with a dynamic name
        if Model.objects.filter(**{token_field:token}).count() is 0:
            unique_token_found = True
    return token
    

    然后,您只需调用即可找到唯一令牌

    token = generate_unique_token(MyModelInstance, "token_field_name")
    

    它甚至支持使用其他生成令牌的方法。例如,如果你想使用完整的 uuid,你可以简单地这样调用它:

    token = generate_unique_token(MyModel, "token_field_name", lambda: uuid.uuid4().hex)
    

    【讨论】:

    • 这似乎没有必要?取决于算法,Guids/uuids 不是几乎可以保证是唯一的吗?
    • 也许可以,但如果你想获得更短的令牌,这真的很有用,
    • 是的,UUID 的用途是……以它的名义!通用唯一 ID!这是一个非常奇怪的答案。
    • UUID 具有相当长的不幸特性。如果您只是截断令牌,那么您将牺牲碰撞阻力。然后,您不能只是简单地将令牌保存到数据库中并假设令牌将是唯一的。
    【解决方案5】:

    一种可能的解决方案是使用 AES 加密令牌过期的时间 ​​+ 用户名,这样可以很容易地发现过期的令牌并且不需要额外的数据库空间来存放令牌

    【讨论】:

    • 如果有人找到了你的密钥呢?他们将拥有对您网站上所有用户帐户的完全访问权限……这是个坏主意。
    • 这意味着您的服务器安全性较差,或者您只是使用了一个糟糕的密钥,此外您可以将其保存在 ram 中并随机生成它,您的用户在服务器重新启动时会注销,但这听起来不错
    猜你喜欢
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 2023-03-07
    相关资源
    最近更新 更多