web-dev-qa-db-fra.com

Générer un mot de passe en python

Je voudrais générer des mots de passe alphanumériques en python. Certaines manières possibles sont:

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

Mais je n'aime pas les deux parce que:

  • voie 1 uniquement des caractères uniques sélectionnés et vous ne pouvez pas générer de mots de passe où longueur> len (caractères)
  • façon 2 nous avons i variable inutilisée et je ne trouve pas le bon moyen d'éviter cela

Alors, d'autres bonnes options?

P.S. Nous voici donc avec quelques tests avec timeit pour 100 000 itérations:

''.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

Ainsi, le gagnant est ''.join(choice(chars) for _ in xrange(length)).

44
HardQuestions

Python 3.6 et suivants

Vous devez utiliser le module secrets pour générer des mots de passe sûrs sur le plan cryptographique, qui est disponible à partir de Python 3.6. Adapté de la documentation:

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
83
gerrit

Pour les gens de crypto-PRNG là-bas:

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))

Notez que pour une distribution paire, la longueur de chaîne chars doit être un diviseur entier de 128; sinon, vous aurez besoin d'une manière différente de choisir uniformément dans l'espace.

33
Ben Mosher

AVERTISSEMENT cette réponse doit être ignorée en raison de problèmes de sécurité critiques!

L'option n ° 2 semble tout à fait raisonnable, sauf que vous pourriez ajouter quelques améliorations:

''.join(choice(chars) for _ in range(length))          # in py2k use xrange

_ est une variable conventionnelle "Je me fiche de ce qui s'y trouve". Et vous n'avez pas besoin de compréhension de liste là-bas, l'expression du générateur fonctionne très bien pour str.join. Il n'est pas clair non plus ce que signifie "lent", si c'est la seule manière correcte .

13
SilentGhost

Je pense que ça fera l'affaire. random.SystemRandom utilise la même fonction cryptographique aléatoire sous-jacente que os.urandom mais il utilise l'interface familière random. Cette fonction ne sera pas soumise à l'étrange chose de 128 octets comme dans la réponse de Ben.

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
Tim Ludwinski

Je suggère ce qui suit pour ceux qui sont coincés sur 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))])

Cela a l'avantage sur la solution de Ben Mosher que chaque symbole des symboles a un changement égal d'occurrence tandis que l'utilisation du module favorise légèrement les premiers symboles de l'alphabet. L'alphabet des symboles est également plus grand dans cette suggestion.

4
gardarh