这个问题有细微差别,某些解决方案可能会导致password weakness
问题。考虑以下细微差别以及解决方案替代方案。
- 一些答案使用
string.printable
,但这不是一个好主意,因为它包含空格字符。虽然它们对于密码来说并不是严格非法的,但您不能轻易看到它们,因此无法区分,例如,一个制表符和几个空格(等等)。下面我只使用小写字母和大写字母、数字和标点符号。
- 基于元素位置从一组字符中随机选择不是随机的,因为每个包含的字符类的基数不是均匀分布的:26个小写字母;26个大写字母;10位;32个标点符号。因此,生成的密码可能包含比标点字符和数字更多的字母;标点符号多于数字;(等等)。因此,如果
random.choices()
使用(如其他答案),还应该使用它weights=
和cum_weights=
选项,以消除上述偏差并平衡分布。
- 也就是说,我鼓励在这个用例中使用 Python 的
secrets
模块而不是它的random
模块。从他们关于 random 的文档中:
警告:此模块的伪随机生成器不应用于安全目的。有关安全或加密用途,请参阅
秘密模块。
这是一个使用Python-3的面向功能的解决方案。它只使用。它并没有完全解决随机问题(其他细微差别仍然存在),但它确实改善了选择分布以减少偏差:secrets.choice()
>>> import string, secrets
>>> char_classes = (string.ascii_lowercase,
string.ascii_uppercase,
string.digits,
string.punctuation)
>>> size = lambda: secrets.choice(range(8,13)) # Chooses a password length.
>>> char = lambda: secrets.choice(secrets.choice(char_classes)) # Chooses one character, uniformly selected from each of the included character classes.
>>> pw = lambda: ''.join([char() for _ in range(size())]) # Generates the variable-length password.
演示:使用从我们每个字符类中统一选择的字符生成 10 个可变长度密码字符串:
>>> for i in range(1,11):
>>> p = pw()
>>> print('%i) %i chars :: %s' % (i,len(p),p))
1) 11 chars :: IwWNEAUmnJt
2) 10 chars :: ;N/'tO6RTv
3) 8 chars :: l=5.2CDh
4) 10 chars :: V0=I+A`t2Q
5) 12 chars :: PQm8:f,#56"9
6) 10 chars :: KOdx9~%r;F
7) 11 chars :: <?67U8}3>F{
8) 11 chars :: G$5y~3fE7o*
9) 10 chars :: 70,|=Rexwn
10) 8 chars :: &31P^@cU
最后,虽然我们在secrets
这里使用了模块,但可以使用numpy
and来完成类似的事情numpy.random
。我希望这有帮助!