Django - make_random_password方法,它真的是随机的吗?

4
我正在使用以下方法作为预订流程的一部分,为用户创建一个随机代码: ```php $random_code = bin2hex(random_bytes(6)); ``` 此代码将生成一个12位十六进制随机代码。
 User.objects.make_random_password()
当用户到达场地时,他们将出示密码。 可以安全地假设两个人不会使用相同的代码吗? 谢谢。

1
标题询问随机性,而内容询问唯一性。这些是完全不同的概念。 - Tadeck
@Tadeck 感谢您的澄清,非常感谢! - Imran Azad
@Tadeck,我完全不同意你的观点。它们并不是完全不同的概念。它们是相辅相成的。如果某物不够随机,那么独特性就无法得到保证。我认为这个问题很有意义。 - Patrick Bassut
此外,如果您深入研究,您在这里提出的问题也是数学中的一个问题。 - Patrick Bassut
4
为了支持我的观点(即随机性与唯一性是分开的),我建议你阅读这篇文章:http://cstheory.stackexchange.com/a/3188/5178 ——他们可能更好地解释了这些区别。对于你所提出的“如果某物不够随机,那么唯一性就无法得到保证”的说法,其中一个反例是A000027序列,它绝对不是随机的,而每个项目都保证是唯一的(这就是为什么它经常用于保证许多关系型数据库管理系统中主键的唯一性)。 - Tadeck
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
5
这取决于您拥有的用户数量、所选择的密码长度以及如何使用User.objects.make_random_password()。对于默认值,我认为几乎没有机会; 此方法是使用get_random_string()实现的。参考django github repo:
def get_random_string(length=12,
                      allowed_chars='abcdefghijklmnopqrstuvwxyz'
                                    'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
    """
Returns a securely generated random string.

The default length of 12 with the a-z, A-Z, 0-9 character set returns
a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
"""
    if not using_sysrandom:
        # This is ugly, and a hack, but it makes things better than
        # the alternative of predictability. This re-seeds the PRNG
        # using a value that is hard for an attacker to predict, every
        # time a random string is required. This may change the
        # properties of the chosen random sequence slightly, but this
        # is better than absolute predictability.
        random.seed(
            hashlib.sha256(
                "%s%s%s" % (
                    random.getstate(),
                    time.time(),
                    settings.SECRET_KEY)
                ).digest())
    return ''.join([random.choice(allowed_chars) for i in range(length)])
根据Github,当前代码默认使用62个字符(大小写字母和数字)的字符串中的12个字符作为密码。这样可以生成62**12或3226266762397899821056(3.22e21)种不同的密码。这比当前世界人口(约7e9)要多得多。 字母是通过random.choice()函数从此字符列表中选择的。现在的问题是,重复调用random.choice()返回相同序列的可能性有多大? 正如您从get_random_string()的实现中所看到的那样,该代码会尽力避免可预测性。当不使用操作系统的伪随机值生成器(在Linux和*BSD上从例如以太网数据包或按键到达的时间中收集真正的随机性)时,它会在每次调用时使用当前随机状态、当前时间和(可能是常数的)秘密密钥的组合重新播种random模块的Mersenne Twister可预测PRNG。 因此,要生成两个相同的密码,必须使随机生成器的状态(在Python中约为8 kiB)和生成它们的时间(以自纪元以来的秒数表示,如time.time())完全相同。如果系统的时间得到良好维护并且您正在运行一个密码生成程序的实例,则发生这种情况的可能性基本为零。如果您同时启动两个或更多个密码生成程序的实例,并且使用PRNG的完全相同的种子组合它们的输出,则可以预期某些密码会出现多次。

5
不,不能假设两个人不会拥有相同的代码,随机并不意味着独一无二。根据您指定的长度和涉及的用户数量而言,这可能是不太可能和罕见的情况。但是您不能依赖其唯一性。

另外,如果你真的想要唯一性,你可以使用随机生成的字符串与计数器值相结合,将其添加到末尾,每次添加用户时都会递增。如果该计数器的宽度足够大以应对你的用户,则可以保证唯一性。 - TJD
感谢简明扼要的回答。 - Imran Azad
我理解每添加一个用户就加1的概念,但是你所说的“计数器的宽度足够大以应对你的用户”是什么意思?能否详细说明一下?非常感谢。 - Imran Azad
这取决于密码生成算法的实现方式。它本质上已经通过在每次调用时使用当前时间和当前状态重新播种PRNG来执行您建议的操作。请参见我的回答。 - Roland Smith
我所说的“计数器宽度”是指如果你使用一个16位计数器,那么你只能计数到65,535,或者一个32位计数器将给你2^32种组合等等。因此,你需要确保你的计数器足够大,可以计算用户数量。 - TJD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,