Создание пароля в python
Мне нужно генерировать несколько буквенно-цифровых паролей в 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
Но мне это не нравится, потому что:
- способ 1 выбраны только уникальные символы, и вы не можете генерировать пароли, где длинa > len (chars)
- способ 2 у нас есть переменная
i
неиспользованная, и я не могу найти хороший способ избежать этого.
Итак, любые другие хорошие варианты?
P.S. Итак, мы тестируем с timeit
для 100000 итераций:
''.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
Итак, победитель ''.join(choice(chars) for _ in xrange(length))
.
Ответы
Ответ 1
Python 3.6 и далее
Вы должны использовать модуль секретов для генерации криптографически безопасных паролей, который доступен начиная с 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
Ответ 2
Для крипто-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))
Обратите внимание, что для четного распределения длина строки chars
должна быть интегральным делителем 128; в противном случае вам понадобится другой способ выбрать одно из пространства.
Ответ 3
ПРЕДУПРЕЖДЕНИЕ. Этот ответ следует игнорировать из-за критических проблем безопасности!
Вариант № 2 выглядит вполне разумным, за исключением того, что вы можете добавить несколько улучшений:
''.join(choice(chars) for _ in range(length)) # in py2k use xrange
_
является обычной переменной "Меня не волнует, что там". И вам не нужно понимать список там, выражение генератора отлично работает для str.join
. Также неясно, что означает "медленный", если это единственный правильный путь.
Ответ 4
Я думаю, это будет трюк. random.SystemRandom
использует ту же основную крипто-случайную функцию, что и os.urandom
но использует знакомый random
интерфейс. Эта функция не будет подвержена странным 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)
Ответ 5
Я предлагаю для тех, кто застрял на python <3.6:
import os, math, string, struct
def generate_password(pass_len):
symbols = string.printable.strip()
return ''.join([symbols[x * len(symbols) / 256] for x in struct.unpack('%dB' % (pass_len,), os.urandom(pass_len))])
Это имеет преимущество перед решением Бена Мошера, что каждый символ из символов имеет равное изменение происходящего, тогда как использование модуля слегка способствует первым символам в альпате. Алфавит символов также больше в этом предположении.
Ответ 6
duhhhh проверить элемент??? Freakin dumbdumb
Ответ 7
Я написал script с моими предпочтениями, которые в основном связаны с тем, чтобы избежать ошибок при расшифровке и запоминании. (Например: удалить несколько неоднозначные и не повторять символы.)
import optparse
import os
import random
import sys
DEFAULT_CHARS = "234679ADEFGHJKLMNPRTUWabdefghijkmnpqrstuwy"
DEFAULT_LEN = 18
def choices(options, length, choice=random.choice):
return (choice(options) for _ in xrange(length))
def choices_non_repeated(options, length, choice=random.choice):
assert len(options) > 1
last = choice(options)
count = 0
while count < length:
yield last
count += 1
while True:
value = choice(options)
if value != last:
last = value
break
def main(args):
op = optparse.OptionParser(add_help_option=False)
op.add_option("--help", action="help",
help="show help message and exit")
op.add_option("-b", "--bare", action="store_true", default=False,
help="print passwords without trailing newline")
op.add_option("-c", "--chars", metavar="SET", nargs=1, default=DEFAULT_CHARS,
help="character set to use (default: %default)")
op.add_option("--repeat", action="store_true", default=False,
help="allow repetition")
op.add_option("-l", "--len", dest="max", nargs=1, type="int", default=DEFAULT_LEN,
help="max length (default: %default)")
op.add_option("--min", nargs=1, type="int", default=None,
help="min length (defaults to max)")
op.add_option("-n", "--count", nargs=1, type="int", default=None,
help="number of passwords to generate (default: %default)")
op.add_option("--cols", type="int", default=None,
help="number of columns to use")
opts, args = op.parse_args(args)
if args:
op.error("unknown arguments")
if os.isatty(sys.stdin.fileno()) and (
opts.count is None and opts.cols is None
and not opts.bare
):
opts.cols = 80 // (opts.max + 1)
opts.count = opts.cols * 25
else:
if opts.count is None:
opts.count = 1
if opts.cols is None:
opts.cols = 1
if opts.bare and opts.cols != 1:
op.error("bare output requires --cols=1")
if opts.min == None:
opts.min = opts.max
if any(x < 1 for x in [opts.cols, opts.count, opts.min, opts.max]):
op.error("values must be >= 1")
choices_func = choices_non_repeated
if opts.repeat:
choices_func = choices
elif len(set(opts.chars)) < 2:
op.error("must allow repetition or provide a longer character set")
return "op.error shouldn't return"
col = 0
for _ in xrange(opts.count):
length = random.randint(opts.min, opts.max)
password = "".join(choices_func(opts.chars, length))
sys.stdout.write(password)
if not opts.bare:
col += 1
if col == opts.cols:
sys.stdout.write("\n")
col = 0
else:
sys.stdout.write(" ")
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Ответ 8
Вы можете использовать map
вместо понимания списка:
''.join(map(lambda x: random.choice(chars), range(length)))