随机密码生成器质量

发布于 2025-02-08 15:54:28 字数 1047 浏览 2 评论 0原文

我被要求根据不同的字符集开发一个随机密码生成器,例如'abcd ..... wxyz','0123456789'和'!$()?=^_;:;:,, .-'。

我现在已经牢记了两个不同的实现:

  1. 在这种情况下,所有字符集已复制到一个字符串中,然后每个构成密码的字符都从中随机获取。
    import os, random, string

    length = 13
    chars = string.ascii_letters + string.digits + '!$()?=^_;:,.-'
    random.seed = (os.urandom(1024))

    print ''.join(random.choice(chars) for i in range(length))
  1. 字符集被划分,并使用随机值在集合之间进行选择,然后从选定的集合中,
    import os, random, string

    length = 13
    set = [string.ascii_letters, string.digits, '!$()?=^_;:,.-']

    random.seed = (os.urandom(1024))

    print ''.join(random.choice(random.choice(set)) for i in range(length))

从多个测试中获取一个随机字符,似乎第二个解决方案会生成包含更多符号和数字的密码,这是应得的对于使用符号的概率恰好是1/3(33%)的事实。而在第一个算法中,只有13/(10+13+26)= 26%。

哪一个是正确的实现?我认为,第一种算法对集合选择具有不均匀的概率,从而更有可能找到符合符号的ascii_letters。 任何提示都将不胜感激。

编辑:我仅用于以快速方式解释两种不同的实现。当然,我会选择最合适的模块,但是现在我对此评估不感兴趣。

I have been asked to develop a random password generator based on different character sets, like 'abcd.....wxyz', '0123456789' and '!$()?=^_;:,.-'.

I have now in mind two different implementations:

  1. In this case, all characters set are copied into a single string, then each character that composes the password is taken randomly from it.
    import os, random, string

    length = 13
    chars = string.ascii_letters + string.digits + '!$()?=^_;:,.-'
    random.seed = (os.urandom(1024))

    print ''.join(random.choice(chars) for i in range(length))
  1. The character sets are divided and a random value is used to select among the sets and then, from that selected set, a random character is taken
    import os, random, string

    length = 13
    set = [string.ascii_letters, string.digits, '!$()?=^_;:,.-']

    random.seed = (os.urandom(1024))

    print ''.join(random.choice(random.choice(set)) for i in range(length))

From multiple tests it seems that the second solution generates passwords that contain more symbols and numbers, this is due to the fact that the probability to use a symbol is exactly 1/3 (33%). While in the first algorithm only 13/(10+13+26) = 26%.

Which one is the correct implementation? I think that the first algorithm has a non-uniform probability with the respect to the set selection, making more probable to find ascii_letters with the respect to the symbols.
Any hints would be appreciated.

Edit: I did this implementation only for explaining the two different implementations in a fast way. Surely I'll select the best suitable module, but for now I'm not interested in this evaluation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

可爱暴击 2025-02-15 15:54:28

第一个解决方案是更好的,因为来自密码的单个字符具有成为任何可能字符的同等可能性。第二个解决方案引入了偏见(有些字符比其他字符更有可能被选择),从而降低了密码的熵(随机性)。如果攻击者知道这是您如何生成密码的方式,则意味着它们更容易破解。


但是,这两者都是生成密码的不好方法,因为用户很难记住和使用这种类型的密码。 and nist> nist 著名的 XKCD )已推荐多年来使用密码。

因此,与其尝试从字符集生成密码,不如从多个单词中生成它们(如果您想提高强度,可能会随机选择的符号或数字)。

The first solution is better, because a single character from the password has an equal probability of being any of the possible characters. The second solution introduces biases (with some characters more likely to be selected than others), which reduces the entropy (randomness) of the password. If an attacker knows this is how you're generating passwords, this means them easier to crack.


However, both of these are bad ways to generate passwords, because this type of password is very difficult for users to remember and use. Organisations like NCSC and NIST (and of course, the famous XKCD) have been recommending the use of passphrases for years.

So rather than trying to generate password from character sets, you should be generating them from multiple words (possibly with randomly selected symbols or numbers between them if you want to increase the strength).

遗弃M 2025-02-15 15:54:28

推荐的方法来自食谱和最佳实践官方Python 秘密文档的部分更接近您的第一个实现:

import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))

您还可以明确指定最小数量的字符类型(例如数字,标点符号):

import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

另外,作为FYI,您可以使用<代码> string.punctuation 将标点字符添加到您的字符串。

The recommended approach from the Recipes and best practices section of the official Python secrets documentation is closer to your first implementation:

import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))

You can also explicitly specify a minimum numbers of character types (e.g. digits, punctuation):

import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

Also, as an FYI, you can use string.punctuation to add punctuation characters to your character string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文