简体   繁体   English

随机密码生成器质量

[英]Random Password Generator quality

I have been asked to develop a random password generator based on different character sets, like 'abcd.....wxyz', '0123456789' and '!$()?=^_;:,.-'.我被要求开发一个基于不同字符集的随机密码生成器,例如'abcd.....wxyz'、'0123456789'和'!$()?=^_;:,.-'。

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%).从多次测试来看,第二种解决方案似乎生成了包含更多符号和数字的密码,这是因为使用符号的概率恰好是 1/3 (33%)。 While in the first algorithm only 13/(10+13+26) = 26%.而在第一个算法中只有 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.我认为第一个算法在集合选择方面具有非均匀概率,从而更有可能找到关于符号的 ascii_letters。 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.当然我会选择最合适的模块,但现在我对这个评估不感兴趣。

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.NCSCNIST (当然还有著名的XKCD )这样的组织多年来一直在推荐使用密码短语。

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).因此,与其尝试从字符集生成密码,不如从多个单词生成它们(如果你想增加强度,可能在它们之间随机选择符号或数字)。

The recommended approach from the Recipes and best practices section of the official Python secrets documentation is closer to your first implementation:官方 Python secrets文档的食谱和最佳实践部分推荐的方法更接近于您的第一个实现:

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 (eg 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.此外,作为仅供参考,您可以使用string.punctuation将标点符号添加到您的字符串中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM