Générer des mots de passe et des jetons sécurisés est un besoin courant dans tout projet logiciel. Bonne nouvelle : Python dispose de tout ce qu’il faut dans sa bibliothèque standard, sans aucune dépendance externe. Cet article présente 10 techniques éprouvées, chacune avec son cas d’usage idéal.
Règle d’or : pour tout ce qui touche à la sécurité, utilisez le module secrets (Python 3.6+). Le module random n’est pas cryptographiquement sûr et ne doit jamais être utilisé pour des mots de passe en production.
1. secrets.token_urlsafe()
La méthode la plus simple pour générer un jeton sécurisé. Le résultat est encodé en base64 URL-safe, ce qui le rend parfait pour les URLs, les jetons de réinitialisation de mot de passe et les clés API.
import secrets
token = secrets.token_urlsafe(32)
print(token) # ex: Dz-M4Kq9x7R2bN5vLpWs...
print(len(token)) # 43 caractères
Le paramètre 32 correspond au nombre d’octets aléatoires avant l’encodage base64. Le jeton résultant fait environ 43 caractères. C’est la méthode recommandée pour la plupart des cas d’usage.
2. secrets.token_hex()
Génère une chaîne hexadécimale aléatoire. Utile quand vous avez besoin d’un jeton composé uniquement de caractères 0-9 et a-f.
import secrets
token = secrets.token_hex(16)
print(token) # ex: a3f2b1c4d5e6f7081920abcdef123456
print(len(token)) # 32 caractères hexadécimaux
Chaque octet produit deux caractères hexadécimaux. Avec 16 octets, vous obtenez un jeton de 32 caractères offrant 128 bits d’entropie, ce qui est largement suffisant pour la plupart des applications.
3. secrets.token_bytes() + base64
Pour un contrôle total sur l’encodage, combinez secrets.token_bytes() avec le module base64 :
import secrets
import base64
raw = secrets.token_bytes(24)
password = base64.b64encode(raw).decode("ascii")
print(password) # ex: K7vB2mP9xQ4nR1jL8wY3dFhT...
print(len(password)) # 32 caractères
Cette approche est utile lorsque vous devez choisir un encodage spécifique (base64, base32, base85). L’encodage base64 produit un rapport de 4 caractères pour 3 octets.
4. secrets.choice() avec un alphabet alphanumérique
Quand vous avez besoin d’un mot de passe composé uniquement de lettres et de chiffres :
import secrets
import string
alphabet = string.ascii_letters + string.digits
password = "".join(secrets.choice(alphabet) for _ in range(16))
print(password) # ex: aB3kM9pQ2wX7nL5j
Le module string fournit des constantes pratiques : ascii_letters (a-z + A-Z), digits (0-9), punctuation (caractères spéciaux). secrets.choice() sélectionne un caractère aléatoire de manière cryptographiquement sûre.
5. secrets.choice() avec caractères spéciaux (et garantie de complexité)
Pour des mots de passe qui satisfont les exigences de complexité (majuscule, minuscule, chiffre, caractère spécial) :
import secrets
import string
def mot_de_passe_fort(longueur=16):
alphabet = string.ascii_letters + string.digits + "!@#$%&*+-_"
while True:
mdp = "".join(secrets.choice(alphabet) for _ in range(longueur))
if (any(c in string.ascii_lowercase for c in mdp)
and any(c in string.ascii_uppercase for c in mdp)
and any(c in string.digits for c in mdp)
and any(c in "!@#$%&*+-_" for c in mdp)):
return mdp
print(mot_de_passe_fort()) # ex: aB3$kM9&pQ2!wX7@
print(mot_de_passe_fort(24)) # version plus longue
La boucle while True régénère le mot de passe jusqu’à ce qu’il contienne au moins un caractère de chaque catégorie. En pratique, avec un alphabet large et une longueur de 16+, la boucle ne fait qu’une ou deux itérations.
6. os.urandom() + base64
Le module os donne accès au générateur d’entropie du système d’exploitation. C’est d’ailleurs la source que secrets utilise en interne.
import os
import base64
raw = os.urandom(32)
token = base64.urlsafe_b64encode(raw).decode("ascii").rstrip("=")
print(token) # ex: Dz-M4Kq9x7R2bN5vLpWs...
print(len(token)) # 43 caractères
Cette technique est équivalente à secrets.token_urlsafe() mais vous donne un contrôle plus fin. Elle est utile si vous travaillez avec Python 2 ou un environnement où secrets n’est pas disponible.
7. uuid.uuid4() pour des identifiants uniques
Les UUID version 4 sont générés aléatoirement et offrent 122 bits d’entropie. Ils sont parfaits comme identifiants uniques, mais ne sont pas recommandés comme mots de passe car leur format est prévisible.
import uuid
token = str(uuid.uuid4())
print(token) # ex: 550e8400-e29b-41d4-a716-446655440000
# Version compacte (sans tirets)
compact = token.replace("-", "")
print(compact) # ex: 550e8400e29b41d4a716446655440000
print(len(compact)) # 32 caractères
Les UUID sont idéaux pour les identifiants de session, les clés primaires de base de données ou les noms de fichiers temporaires. Leur format standardisé les rend facilement reconnaissables.
8. hashlib + secrets pour des jetons dérivés
Combinez hashlib et secrets pour créer des jetons de longueur fixe, parfaits pour des signatures ou des clés de vérification :
import hashlib
import secrets
salt = secrets.token_bytes(16)
data = secrets.token_bytes(32)
token = hashlib.sha256(salt + data).hexdigest()
print(token) # 64 caractères hexadécimaux
print(len(token)) # toujours 64
Le sel (salt) rend chaque jeton unique même si les données d’entrée étaient identiques. SHA-256 produit toujours exactement 64 caractères hexadécimaux. Vous pouvez aussi utiliser sha512 pour un jeton de 128 caractères.
9. random (NON sécurisé – à éviter en production)
Attention : le module random utilise l’algorithme Mersenne Twister qui n’est pas cryptographiquement sûr. Son état interne peut être reconstitué à partir de 624 valeurs consécutives. Ne l’utilisez jamais pour des mots de passe en production.
import random
import string
# ATTENTION : NON cryptographiquement sur !
# A utiliser UNIQUEMENT pour des tests ou des donnees non sensibles
alphabet = string.ascii_letters + string.digits
password = "".join(random.choice(alphabet) for _ in range(16))
print(password)
Le seul cas acceptable pour random est la génération de données de test ou de mots de passe jetables dans un contexte de développement local. Pour tout le reste, utilisez secrets.
10. Générateur configurable tout-en-un
Voici une fonction réutilisable qui combine les meilleures pratiques et permet de personnaliser chaque aspect du mot de passe généré :
import secrets
import string
def generer_mot_de_passe(
longueur=16,
majuscules=True,
minuscules=True,
chiffres=True,
speciaux=True,
caracteres_speciaux="!@#$%&*+-_=",
):
alphabet = ""
requis = []
if minuscules:
alphabet += string.ascii_lowercase
requis.append(secrets.choice(string.ascii_lowercase))
if majuscules:
alphabet += string.ascii_uppercase
requis.append(secrets.choice(string.ascii_uppercase))
if chiffres:
alphabet += string.digits
requis.append(secrets.choice(string.digits))
if speciaux:
alphabet += caracteres_speciaux
requis.append(secrets.choice(caracteres_speciaux))
if not alphabet:
raise ValueError("Au moins un type de caractère doit être activé")
reste = longueur - len(requis)
mdp = requis + [secrets.choice(alphabet) for _ in range(reste)]
secrets.SystemRandom().shuffle(mdp)
return "".join(mdp)
print(generer_mot_de_passe())
print(generer_mot_de_passe(longueur=32, speciaux=False))
print(generer_mot_de_passe(longueur=8, caracteres_speciaux="!@#"))
Cette fonction garantit qu’au moins un caractère de chaque catégorie activée est présent dans le mot de passe final. Le mélange aléatoire via secrets.SystemRandom().shuffle() assure que les caractères obligatoires ne sont pas toujours au début.
Récapitulatif
Voici un résumé rapide pour choisir la bonne technique selon votre besoin :
– Jeton URL-safe : secrets.token_urlsafe()
– Jeton hexadécimal : secrets.token_hex()
– Encodage personnalisé : secrets.token_bytes() + base64
– Mot de passe alphanumérique : secrets.choice() + string
– Mot de passe complexe : secrets.choice() avec validation
– Compatibilité bas niveau : os.urandom()
– Identifiant unique : uuid.uuid4()
– Jeton de longueur fixe : hashlib + secrets
Quelle que soit la technique choisie, retenez la règle essentielle : utilisez toujours le module secrets pour tout ce qui concerne la sécurité. Votre futur vous en remerciera.

Laisser un commentaire