在python中生成密码

Har*_*ons 47 python passwords

我想在python中生成一些字母数字密码.一些可能的方法是:

import string
from random import sample, choice
chars = string.letters + string.digits
length = 8
''.join(sample(chars,length)) # way 1
''.join([choice(chars) for i in range(length)]) # way 2
Run Code Online (Sandbox Code Playgroud)

但我不喜欢两者,因为:

  • 方式1只选择了唯一的字符,你不能生成密码长度> len(字符)
  • 方式2我们有i变量未使用,我找不到如何避免这种情况的好方法

那么,还有其他好的选择吗?

PS所以这里我们正在进行一些timeit100000次迭代的测试:

''.join(sample(chars,length)) # way 1; 2.5 seconds
''.join([choice(chars) for i in range(length)]) # way 2; 1.8 seconds (optimizer helps?)
''.join(choice(chars) for _ in range(length)) # way 3; 1.8 seconds
''.join(choice(chars) for _ in xrange(length)) # way 4; 1.73 seconds
''.join(map(lambda x: random.choice(chars), range(length))) # way 5; 2.27 seconds
Run Code Online (Sandbox Code Playgroud)

所以,获胜者是''.join(choice(chars) for _ in xrange(length)).

ger*_*rit 92

Python 3.6起

您应该使用secrets模块生成加密安全密码,从Python 3.6开始提供.改编自文档:

import secrets
import string
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(20)) # for a 20-character password
Run Code Online (Sandbox Code Playgroud)


Ben*_*her 33

对于那里的加密PRNG人员:

def generate_temp_password(length):
    if not isinstance(length, int) or length < 8:
        raise ValueError("temp password must have positive length")

    chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
    from os import urandom
    return "".join(chars[ord(c) % len(chars)] for c in urandom(length))
Run Code Online (Sandbox Code Playgroud)

注意,对于均匀分布,chars字符串长度应该是128的整数除数; 否则,你需要一种不同的方式从空间中统一选择.


Sil*_*ost 13

警告由于严重的安全问题,应忽略此答案!

选项#2似乎很合理,除了你可以添加一些改进:

''.join(choice(chars) for _ in range(length))          # in py2k use xrange
Run Code Online (Sandbox Code Playgroud)

_是一个传统的"我不在乎那里有什么"变量.而且你不需要那里的列表理解,生成器表达式就可以了str.join.如果它是唯一正确的方法,也不清楚"慢"意味着什么.

  • 您应该使用安全随机数生成器来生成密码,否则您的密码可能很容易受到攻击.默认的python RNG不是安全的."Python使用Mersenne Twister作为核心生成器...... Mersenne Twister ......完全不适合加密目的." -http://docs.python.org/library/random.html (39认同)
  • 我想在此备份Fasaxc.请查看@ livibetter的评论,使用[PEP0506]中的[secrets](https://docs.python.org/3.6/library/secrets.html)模块(https://www.python.org/dev/peps/PEP-0506 /).正如livibetter所说,本文被引用为一个不好的例子.我知道这是一个我正在评论的老问题,但它仍然是最热门的搜索结果之一.我建议有人改变接受gerrit的答案. (3认同)

np8*_*np8 10

使用内置秘密的两个食谱(python 3.6+)

1.secrets.token_urlsafe

这比接受的答案快得多。(见下面的时间)

import secrets
password = secrets.token_urlsafe(32)
Run Code Online (Sandbox Code Playgroud)

示例输出:

4EPn9Z7RE3l6jtCxEy7CPhia2EnYDEkE6N1O3-WnntU
Run Code Online (Sandbox Code Playgroud)

的参数token_urlsafe是字节数。平均而言,一个字节是 1.3 个字符(base64 编码)。

2.强制执行数字/大写字符等

这是从秘密文档中略加修改的副本。有了这个,您可以更精细地控制如何生成密码。当然,如果您需要生成大量密码,这不是一个快速的选择。

  • 强制长度为 20 个字符
  • 强制至少 4 个小写字符
  • 强制至少 4 个大写字符
  • 强制至少 4 位数字
  • 可以将特殊字符添加到alphabet. 在这个例子中,有 just-_added。
4EPn9Z7RE3l6jtCxEy7CPhia2EnYDEkE6N1O3-WnntU
Run Code Online (Sandbox Code Playgroud)

示例输出:

HlxTm2fcFE54JA1I_Yp5
Run Code Online (Sandbox Code Playgroud)

3.“我不需要更细粒度的控制”

如果考虑速度,您还可以删除 while 循环。在这种情况下,它实际上简化了 gerrit 的答案(但随后您失去了更细粒度的控制):

import string
import secrets
alphabet = string.ascii_letters + string.digits + '-_'
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(20))
    if (sum(c.islower() for c in password) >=4
            and sum(c.isupper() for c in password) >=4
            and sum(c.isdigit() for c in password) >=4):
        break
Run Code Online (Sandbox Code Playgroud)

速度对比

1.secrets.token_urlsafe

1.62 µs ± 96.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Run Code Online (Sandbox Code Playgroud)

2.强制执行数字/大写字符等

107 µs ± 11.9 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Run Code Online (Sandbox Code Playgroud)

3.“我不需要更细粒度的控制”

77.2 µs ± 9.31 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Run Code Online (Sandbox Code Playgroud)

速度比较设置:Win10 上的 python 3.8.5 64 位,每个密码 43 个字符(= 32 字节的 token_urlsafe)。


Tim*_*ski 5

我想这就行了.random.SystemRandom使用相同的底层加密随机函数,os.urandom但它使用熟悉的random界面.这个函数不会像Ben的答案那样受到奇怪的128字节的影响.

import random
import string

def gen_random_string(char_set, length):
    if not hasattr(gen_random_string, "rng"):
        gen_random_string.rng = random.SystemRandom() # Create a static variable
    return ''.join([ gen_random_string.rng.choice(char_set) for _ in xrange(length) ])

password_charset = string.ascii_letters + string.digits
gen_random_string(password_charset, 32)
Run Code Online (Sandbox Code Playgroud)