Gestion des mots de passe dans Django¶
La gestion des mots de passe est quelque chose qui ne devrait généralement pas être réinventé sans raison, et Django s’efforce de fournir un ensemble d’outils sécurisés et souples pour gérer les mots de passe des utilisateurs. Ce document présente la façon dont Django stocke les mots de passe, la configuration possible du hachage avant stockage et certains utilitaires pour manipuler les empreintes de mots de passe.
Voir aussi
Même si les utilisateurs utilisent des mots de passe forts, des attaquants peuvent arriver à écouter leurs connexions. Utilisez HTTPS afin d’éviter d’envoyer des mots de passe (ou d’autres données sensibles) sur des connexions HTTP simples car celles-ci sont vulnérables à l’interception de mots de passe.
Stockage des mots de passe par Django¶
Django fournit un système de stockage de mots de passe souple et emploie PBKDF2 par défaut.
L’attribut password
d’un objet User
est une chaîne dans ce format :
<algorithm>$<iterations>$<salt>$<hash>
Il s’agit des composants utilisés pour stocker le mot de passe d’un utilisateur, séparés par le caractère dollar et formés de : l’algorithme de hachage, le nombre d’itérations de l’algorithme (facteur travail), le sel aléatoire et l’empreinte de mot de passe résultante. L’algorithme correspond à l’un des algorithmes de stockage de mot de passe ou de hachage à sens unique que Django peut utiliser ; voir ci-dessous. Les itérations indiquent le nombre de fois que l’algorithme traite l’empreinte numérique. Le sel est la graine aléatoire utilisée et l’empreinte est le résultat de la fonction à sens unique.
Par défaut, Django utilise l’algorithme PBKDF2 avec une fonction de hachage SHA256, un mécanisme d’étirement de mot de passe recommandé par le NIST. Cela devrait suffire pour la plupart des utilisateurs : c’est un algorithme bien sécurisé et exigeant d’énormes quantités de puissance de calcul pour être cassé.
Cependant, en fonction de vos exigences, vous pouvez choisir un algorithme différent ou même utiliser un algorithme qui vous est propre pour répondre à votre situation spécifique en matière de sécurité. Encore une fois, la plupart des utilisateurs n’auront pas à le faire et si vous n’êtes pas sûr, c’est que vous n’en avez probablement pas besoin. Si vous en avez besoin, continuez cette lecture…
Django choisit l’algorithme à utiliser en consultant le réglage PASSWORD_HASHERS
. Il s’agit d’une liste de classes d’algorithme de hachage que la présente installation de Django prend en charge.
Pour le stockage des mots de passe, Django utilise le premier algorithme de PASSWORD_HASHERS
. Pour stocker les nouveaux mots de passe avec un algorithme différent, placez votre algorithme préféré en première position dans PASSWORD_HASHERS
.
Pour la vérification des mots de passe, Django recherche dans la liste l’algorithme de hachage qui correspond au nom d’algorithme dans le mot de passe stocké. Dans le cas où un nom d’algorithme stocké dans un mot de passe n’est pas trouvé dans PASSWORD_HASHERS
, sa vérification génère une exception ValueError
.
La valeur par défaut de PASSWORD_HASHERS
est :
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
]
Cela signifie que Django utilisera PBKDF2 pour stocker tous les mots de passe, mais qu’il acceptera de vérifier des mots de passe stockés avec les algorithmes PBKDF2SHA1, argon2 et bcrypt.
Les sections qui suivent présentent quelques manières fréquentes que les utilisateurs avancés peuvent utiliser pour modifier ce réglage.
Utilisation de Argon2 avec Django¶
Argon2 est le gagnant du concours 2015 Password Hashing Competition, une compétition ouverte organisée par la communauté pour sélectionner un algorithme de hachage de nouvelle génération. Il est conçu pour ne pas être plus facile à calculer sur du matériel dédié qu’il ne l’est sur un processeur ordinaire. La variante par défaut du hacheur de mot de passe Argon2 et Argon2id.
Argon2 n’est pas l’algorithme utilisé par défaut dans Django car il nécessite une bibliothèque tierce. Les experts de Password Hashing Competition recommandent cependant l’utilisation immédiate de Argon2 plutôt que les autres algorithmes pris en charge par Django.
Pour utiliser Argon2id comme algorithme de stockage par défaut, faites ceci :
Installez le paquet argon2-cffi. Cela peut se faire en lançant
python -m pip install django[argon2]
, ce qui est équivalent àpython -m pip install argon2-cffi
(en installant aussi toute version de paquet exigée par le fichierpyproject.toml
de Django).Modifiez
PASSWORD_HASHERS
pour queArgon2PasswordHasher
apparaisse en premier. Voici ce qui devrait apparaître dans votre fichier de réglages :PASSWORD_HASHERS = [ "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ]
Conservez ou ajoutez d’autres éléments dans cette liste si vous avez besoin que Django puisse mettre à jour des mots de passe.
Utilisation de bcrypt
avec Django¶
Bcrypt est un algorithme de stockage de mot de passe répandu qui est spécifiquement conçu comme stockage de mots de passe à long terme. Ce n’est pas l’algorithme par défaut de Django car il dépend de l’installation de bibliothèques tierces. Mais comme il y a beaucoup d’utilisateurs potentiels, Django prend en charge bcrypt avec un minimum d’effort.
Pour utiliser Bcrypt comme algorithme de stockage par défaut, faites ceci :
Installez le paquet bcrypt. Cela peut se faire en lançant
python -m pip install django[bcrypt]
, ce qui est équivalent àpython -m pip install bcrypt
(en installant aussi toute version de paquet exigée par le fichierpyproject.toml
de Django).Modifiez
PASSWORD_HASHERS
pour queBCryptSHA256PasswordHasher
apparaisse en premier. Voici ce qui devrait apparaître dans votre fichier de réglages :PASSWORD_HASHERS = [ "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ]
Conservez ou ajoutez d’autres éléments dans cette liste si vous avez besoin que Django puisse mettre à jour des mots de passe.
Et voilà, votre installation Django utilise dorénavant Bcrypt comme algorithme de stockage par défaut.
Utilisation de scrypt
avec Django¶
scrypt est semblable à PBKDF2 et à bcrypt dans le sens où il utilise un nombre d’itérations pour ralentir les attaques par force brute. Cependant, comme PBKDF2 et bcrypt ne nécessitent pas beaucoup de mémoire, des attaquants avec suffisamment de ressources peuvent lancer des attaques en parallèle et à large échelle afin d’accélérer le processus d’attaque. scrypt est spécifiquement conçu pour utiliser plus de mémoire en comparaison d’autres fonctions de dérivation de clé basées sur des mots de passe, afin de limiter la capacité de parallélisme d’un éventuel attaquant. Voir RFC 7914 pour plus de détails.
Pour utiliser scrypt comme algorithme de stockage par défaut, faites ceci :
Modifiez
PASSWORD_HASHERS
pour queScryptPasswordHasher
apparaisse en premier. Voici ce qui devrait apparaître dans votre fichier de réglages :PASSWORD_HASHERS = [ "django.contrib.auth.hashers.ScryptPasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", ]
Conservez ou ajoutez d’autres éléments dans cette liste si vous avez besoin que Django puisse mettre à jour des mots de passe.
Note
scrypt
nécessite OpenSSL 1.1+.
Augmentation de l’entropie du sel¶
La plupart de hacheurs de mots de passe incluent un sel dans l’empreinte du mot de passe afin de protéger contre les attaques par table arc-en-ciel. Le sel est lui-même une valeur aléatoire qui augmente la taille et donc le coût de la table arc-en-ciel ; elle possède actuellement 128 bits par la valeur salt_entropy
dans BasePasswordHasher
. Comme les coûts de calcul et de stockage diminuent avec le temps, cette valeur doit augmenter. Si vous implémentez votre propre hacheur de mots de passe, vous êtes libre de surcharger cette valeur pour atteindre le niveau d’entropie souhaité pour votre hacheur de mots de passe. salt_entropy
est une mesure en bits.
Détails d’implémentation
En raison de la méthode avec laquelle les valeurs de sel sont stockées, la valeur salt_entropy
est effectivement une valeur minimale. Par exemple, une valeur de 128 produit un sel qui contient en réalité 131 bits d’entropie.
Augmentation du facteur travail¶
PBKDF2 et bcrypt¶
Les algorithmes PBKDF2 et bcrypt utilisent un certain nombre d’itérations ou de passes de hachage. Cela ralentit volontairement les attaques, rendant plus difficiles les attaques contre les empreintes de mots de passe. Cependant, au fur et à mesure de l’augmentation des puissances de calcul, le nombre d’itérations nécessaires augmente également. Nous avons opté pour une valeur par défaut raisonnable (et nous l’augmenterons avec chaque nouvelle publication de Django), mais vous pouvez l’augmenter ou la réduire en fonction de vos besoins de sécurité et de vos capacités en puissance de calcul. Pour cela, vous pouvez créer une sous-classe de l’algorithme approprié et surcharger le paramètre iterations
(utilisez le paramètre rounds
lors d’un héritage du hacheur bcrypt). Par exemple, pour augmenter le nombre d’itérations utilisé par l’algorithme par défaut PBKDF2 :
Créez une sous-classe de
django.contrib.auth.hashers.PBKDF2PasswordHasher
:from django.contrib.auth.hashers import PBKDF2PasswordHasher class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher): """ A subclass of PBKDF2PasswordHasher that uses 100 times more iterations. """ iterations = PBKDF2PasswordHasher.iterations * 100
Enregistrez-la quelque part dans votre projet. Par exemple, vous pourriez la placer dans un fichier nommé
myproject/hashers.py
.Ajoutez votre nouvelle classe de hachage en premier dans
PASSWORD_HASHERS
:PASSWORD_HASHERS = [ "myproject.hashers.MyPBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", "django.contrib.auth.hashers.ScryptPasswordHasher", ]
Et voilà, votre installation Django utilise dorénavant plus d’itérations lorsqu’elle stockera les mots de passe avec PBKDF2.
Note
Le paramètre rounds
de bcrypt est un facteur de travail logarithmique, par ex. 12 rounds signifie 2 ** 12
itérations.
Argon2¶
Argon2 possède les attributs suivants qui peuvent être personnalisés :
time_cost
contrôle le nombre d’itérations pour l’empreinte.memory_cost
contrôle la taille mémoire utilisée lors du calcul de l’empreinte.parallelism
contrôle le nombre de processeurs pouvant être mis à contribution pour le calcul de l’empreinte.
Les valeurs par défaut de ces attributs sont probablement raisonnables. Si vous déterminez que le hachage des mots de passe est trop rapide ou trop lent, vous pouvez les ajuster comme suit :
- Définissez
parallelism
au nombre de fils d’exécution à exploiter pour le calcul de l’empreinte. - Définissez
memory_cost
au nombre de Kio de mémoire à exploiter. - Ajustez
time_cost
et mesurez le temps passé à hacher un mot de passe. Choisissez une valeurtime_cost
qui consomme un temps acceptable pour vous. Sitime_cost
défini à 1 est encore trop lent, baissez la valeurmemory_cost
.
Interprétation de memory_cost
L’utilitaire en ligne de commande argon2 et certaines autres bibliothèques interprètent le paramètre memory_cost
différemment de la valeur que Django utilise. La conversion est donnée par memory_cost == 2 ** memory_cost_en_ligne_de_commande
.
scrypt
¶
scrypt possède les attributs suivants qui peuvent être personnalisés :
work_factor
contrôle le nombre d’itérations pour l’empreinte.block_size
parallelism
contrôle le nombre de fils d’exécution lancés en parallèle.maxmem
limite la taille mémoire maximale pouvant être utilisée lors du calcul de l’empreinte. La velur par défaut est0
, ce qui indique que c’est la valeur par défaut de la bibliothèque OpenSSL qui sera utilisée.
Nous avons choisi des valeurs par défaut raisonnable, mais vous pouvez les ajuster vers le haut ou vers le bas en fonction de vox exigences de sécurité et de votre puissance de calcul disponible.
Estimation de l’utilisation de la mémoire
L’exigence minimale de mémoire pour scrypt est
work_factor * 2 * block_size * 64
ce qui implique que vous pourriez devoir ajuster maxmem
lorsque vous modifiez les valeurs de work_factor
ou block_size
.
Mise à niveau des mots de passe¶
Lorsque les utilisateurs se connectent, si leur mot de passe est stocké avec un autre algorithme que celui qui est défini comme le principal, Django met automatiquement à jour l’algorithme pour utiliser ce dernier. Cela signifie que d’anciennes installations de Django deviennent automatiquement plus sécurisées au fur et à mesure que les utilisateurs se connectent, et cela signifie également que vous pouvez passer à de nouveaux (et meilleurs) algorithmes de stockage au moment où ils deviennent disponibles.
Cependant, Django peut uniquement mettre à jour les mots de passe utilisant des algorithmes mentionnés dans PASSWORD_HASHERS
, il est donc important de ne pas enlever les anciens algorithmes de cette liste quand vous passez à de nouveaux systèmes. Si vous le faites, les utilisateurs utilisant des algorithmes non mentionnés ne pourront pas mettre à jour leur mot de passe. Les mots de passe hachés sont mis à jour lorsque le nombre d’itérations PBKDF2, de tours bcrypt ou d’attributs argon2 est augmenté (ou réduit).
Soyez conscients que si tous les mots de passe de votre base de données se sont pas codés avec l’algorithme de hachage par défaut, il est possible que vous soyez vulnérable à une attaque de type énumération de compte basée sur le temps en raison d’une différence entre la durée d’une requête de connexion pour un utilisateur avec mot de passe codé dans un algorithme différent et la durée d’une requête de connexion d’un utilisateur non existant (qui exécute l’algorithme par défaut). Il est possible de relativiser ce problème en mettant à jour les anciennes empreintes de mot de passe.
Mise à jour des mots de passe sans exiger de connexion¶
Si une base de données existante comporte des empreintes de mots de passe anciennes et vulnérables de type MD5, il peut être souhaitable de mettre à jour ces empreintes sans devoir attendre que les utilisateurs concernés se connectent (ce qui pourrait ne jamais arriver si ces utilisateurs ne reviennent plus sur le site). Dans ce cas, vous pouvez utiliser un hacheur de mots de passe « enveloppé ».
Pour cet exemple, nous allons migrer une série d’empreintes MD5 afin qu’elles utilisent PBKDF2(MD5(mot_de_passe)) et ajouter le hacheur de mot de passe correspondant qui se chargera de vérifier le mot de passe de l’utilisateur lors d’une connexion. Nous partons du principe que c’est le modèle d’utilisateur par défaut qui est utilisé et que le projet possède une application accounts
. Vous pouvez modifier cet exemple pour qu’il fonctionne avec tout autre algorithme ou avec un modèle d’utilisateur personnalisé.
Nous allons d’abord ajouter le hacheur personnalisé :
from django.contrib.auth.hashers import (
PBKDF2PasswordHasher,
MD5PasswordHasher,
)
class PBKDF2WrappedMD5PasswordHasher(PBKDF2PasswordHasher):
algorithm = "pbkdf2_wrapped_md5"
def encode_md5_hash(self, md5_hash, salt, iterations=None):
return super().encode(md5_hash, salt, iterations)
def encode(self, password, salt, iterations=None):
_, _, md5_hash = MD5PasswordHasher().encode(password, salt).split("$", 2)
return self.encode_md5_hash(md5_hash, salt, iterations)
La migration de données pourrait ressembler à ceci :
from django.db import migrations
from ..hashers import PBKDF2WrappedMD5PasswordHasher
def forwards_func(apps, schema_editor):
User = apps.get_model("auth", "User")
users = User.objects.filter(password__startswith="md5$")
hasher = PBKDF2WrappedMD5PasswordHasher()
for user in users:
algorithm, salt, md5_hash = user.password.split("$", 2)
user.password = hasher.encode_md5_hash(md5_hash, salt)
user.save(update_fields=["password"])
class Migration(migrations.Migration):
dependencies = [
("accounts", "0001_initial"),
# replace this with the latest migration in contrib.auth
("auth", "####_migration_name"),
]
operations = [
migrations.RunPython(forwards_func),
]
Il faut savoir que cette migration va prendre plusieurs minutes pour quelques milliers d’utilisateurs, en fonction de la performance de votre matériel.
Pour terminer, nous allons ajouter un réglage PASSWORD_HASHERS
:
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"accounts.hashers.PBKDF2WrappedMD5PasswordHasher",
]
Incluez tout autre hacheur utilisé par votre site dans cette liste.
Hacheurs de mots de passe intégrés¶
La liste complète de hacheurs de mots de passe inclus dans Django est :
[
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.BCryptPasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
"django.contrib.auth.hashers.MD5PasswordHasher",
]
Les noms d’algorithmes correspondants sont :
pbkdf2_sha256
pbkdf2_sha1
argon2
bcrypt_sha256
bcrypt
scrypt
md5
Écriture de son propre algorithme de hachage¶
Si vous écrivez votre propre algorithme de hachage de mot de passe doté d’un facteur de travail tel qu’un nombre d’itérations, vous devriez implémenter une méthode harden_runtime(self, password, encoded)
pour compenser la différence de temps d’exécution entre le facteur de travail fourni dans le mot de passe encoded
et le facteur de travail par défaut de l’algorithme. Ceci empêche les attaques de type énumération de compte basée sur le temps qui utilise la différence entre les requêtes de connexion d’un utilisateur dont le mot de passe est codé avec un ancien nombre d’itérations et un utilisateur inexistant (qui fait appel au nombre d’itérations par défaut de l’algorithme).
En prenant PBKDF2 comme exemple, si encoded
contient 20’000 itérations et que le nombre d’itérations par défaut de l’algorithme est de 30’000, la méthode devrait faire passer password
à travers 10’000 itérations supplémentaires de PBKDF2.
Si votre algorithme de hachage ne possède pas de facteur de travail, implémentez la méthode comme fictive (pass
).
Gestion manuelle des mots de passe¶
Le module django.contrib.auth.hashers
fournit un ensemble de fonctions pour créer et valider les empreintes de mots de passe. Vous pouvez les utiliser indépendamment du modèle User
.
-
acheck_password
(password, encoded, asetter=None, preferred='default')¶ Version asynchrone:
acheck_password()
Si vous souhaitez authentifier manuellement un utilisateur en comparant un mot de passe en clair à l’empreinte du mot de passe dans la base de données, utilisez la fonction
check_password()
. Elle prend deux arguments obligatoires : le mot de passe en clair à vérifier et la valeur complète du champpassword
d’un utilisateur dans la base de données avec laquelle la vérification sera faite. Si le mot de passe est correcte, la fonction renvoieTrue
, sinonFalse
. Il est possible de transmettre en option un objet exécutablesetter
qui prend un mot de passe en paramètre et qui sera appelé au moment de le régénérer. Vous pouvez aussi transmettrepreferred
pour modifier l’algorithme de hachage si vous ne souhaitez pas utiliser l’algorithme par défaut (première ligne du réglagePASSWORD_HASHERS
). Voir Hacheurs de mots de passe intégrés pour le nom d’algorithme de chaque hacheur.Changed in Django 5.0:La méthode
acheck_password()
a été ajoutée.
-
make_password
(password, salt=None, hasher='default')[source]¶ Crée une empreinte de mot de passe au format utilisé par cette application. Elle demande un paramètre obligatoire : le mot de passe en clair (chaîne ou octets). Il est aussi possible de fournir un sel et un algorithme de hachage à utiliser, si vous ne souhaitez pas utiliser les valeurs par défaut (première ligne du réglage
PASSWORD_HASHERS
). Voir Hacheurs de mots de passe intégrés pour le nom d’algorithme de chaque hacheur de mots de passe. Si le paramètre du mot de passe vautNone
, un mot de passe inutilisable est renvoyé (un mot de passe qui fera quecheck_password()
renvoie toujoursFalse
) .
-
is_password_usable
(encoded_password)[source]¶ Renvoie
False
si le mot de passe a été produit parUser.set_unusable_password()
.
Validation des mots de passe¶
Les utilisateurs choisissent souvent des mots de passe faibles. Pour aider à résoudre ce problème, Django offre une validation des mots de passe à options. Vous pouvez configurer plusieurs validateurs de mots de passe en parallèle. Quelques-uns sont inclus dans Django, mais vous pouvez aussi écrire votre propre validateur.
Chaque validateur de mot de passe doit fournir un texte d’aide pour expliquer les exigences aux utilisateurs, la validation d’un mot de passe donné et un message d’erreur si le mot de passe ne respecte pas les exigences. Facultativement, il peut définir une fonction de rappel afin d’être averti lorsque le mot de passe d’un utilisateur a été changé. Les validateurs peuvent également proposer des réglages facultatifs pour spécialiser leur comportement.
La validation est contrôlée par le réglage AUTH_PASSWORD_VALIDATORS
. La liste de ce réglage est vide par défaut, ce qui signifie qu’aucun validateur n’est appliqué. Dans les nouveaux projets créés par le modèle startproject
par défaut, un ensemble de validateurs sont activés.
Par défaut, les validateurs sont utilisés dans les formulaires pour réinitialiser ou modifier les mots de passe, ainsi que dans les commandes d’administration createsuperuser
et changepassword
. Les validateurs ne sont pas appliqués au niveau des modèles, par exemple dans User.objects.create_user()
et create_superuser()
, parce qu’à ce niveau ce sont les développeurs et non les utilisateurs qui interagissent avec Django et également parce que la validation des modèles n’est pas automatiquement exécutée dans le contexte de la création de modèles.
Note
La validation des mots de passe peut éviter l’emploi de différents types de mots de passe faibles. Cependant, même si un mot de passe est validé par tous les validateurs, cela ne garantit pas forcément un mot de passe solide. Il existe de nombreux facteurs affaiblissant la solidité d’un mot de passe et qui ne peuvent pas être détectés par les validateurs de mots de passe même les plus avancés.
Activation de la validation des mots de passe¶
La validation des mots de passe est configurée par le réglage AUTH_PASSWORD_VALIDATORS
:
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
"OPTIONS": {
"min_length": 9,
},
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
Cet exemple active les quatre validateurs intégrés :
UserAttributeSimilarityValidator
, qui vérifie la similitude entre le mot de passe et certains attributs de l’utilisateur.MinimumLengthValidator
, qui vérifie la longueur minimale du mot de passe. Ce validateur est configuré avec une option personnalisée : il exige une longueur minimale de 9 caractères, au lieu des 8 par défaut.CommonPasswordValidator
, qui vérifie si le mot de passe se trouve dans une liste de mots de passe courants. Par défaut, cette comparaison se fait avec une liste de 20’000 mots de passe courants.NumericPasswordValidator
, qui vérifie que le mot de passe n’est pas entièrement numérique.
Pour UserAttributeSimilarityValidator
et CommonPasswordValidator
, nous utilisons les réglages par défaut dans cet exemple. NumericPasswordValidator
ne contient pas de réglages.
Les textes d’aide et les messages d’erreur des validateurs de mots de passe sont toujours renvoyés dans l’ordre de leur apparition dans AUTH_PASSWORD_VALIDATORS
.
Validateurs intégrés¶
Django fournit quatre validateurs intégrés :
-
class
MinimumLengthValidator
(min_length=8)[source]¶ Valide une longueur minimale des mots de passe. Cette longueur minimale peut être personnalisée avec le paramètre
min_length
.
-
class
UserAttributeSimilarityValidator
(user_attributes=DEFAULT_USER_ATTRIBUTES, max_similarity=0.7)[source]¶ Valide la non-similitude du mot de passe avec plusieurs attributs de l’utilisateur.
Le paramètre
user_attributes
correspond à une itération de noms d’attributs utilisateur avec lesquels la comparaison sera effectuée. Si ce paramètre est omis, la liste par défaut contient :'username', 'first_name', 'last_name', 'email'
. Les attributs qui n’existent pas sont ignorés.La similarité maximale autorisée des mots de passe peut être définie sur une échelle de 0,1 à 1,0 avec le paramètre
max_similarity
. Cette valeur est comparée au résultat dedifflib.SequenceMatcher.quick_ratio()
. Une valeur de 0,1 rejette les mots de passe qui ne sont pas clairement différents des attributsuser_attributes
, alors qu’une valeur de 1,0 ne rejette que les mots de passe qui sont identiques à une valeur d’attribut.
-
class
CommonPasswordValidator
(password_list_path=DEFAULT_PASSWORD_LIST_PATH)[source]¶ Valide que le mot de passe ne correspond pas à un mot de passe courant. Le mot de passe est converti en minuscules (pour effectuer une comparaison insensible à la casse) puis est comparé à une liste de 20’000 mots de passe courants créée par Royce Williams.
password_list_path
peut contenir un chemin vers un fichier personnalisé de mots de passe courants. Ce fichier doit contenir un mot de passe en minuscules par ligne et peut être soit compressé gzip, soit du texte pur.
Intégration de la validation¶
Quelques fonctions dans django.contrib.auth.password_validation
peuvent être appelées depuis vos propres formulaires ou votre code pour intégrer la validation des mots de passe. Cela peut être utile par exemple si vous utilisez des formulaires personnalisés pour la définition des mots de passe ou si vous écrivez des appels d’API permettant la définition de mots de passe.
-
validate_password
(password, user=None, password_validators=None)[source]¶ Valide un mot de passe. Si tous les validateurs estiment que le mot de passe est valide,
None
sera renvoyé. Si un ou plusieurs validateurs rejettent le mot de passe, une exceptionValidationError
est produite contenant tous les messages d’erreur des validateurs.L’objet
user
est facultatif : s’il n’est pas présent, certains validateurs pourraient ne pas être capable de procéder à la validation et accepteront donc n’importe quel mot de passe.
-
password_changed
(password, user=None, password_validators=None)[source]¶ Informe tous les validateurs que le mot de passe a été changé. Cela peut être utilisé par certains validateurs, par exemple pour éviter de réutiliser un même mot de passe. Cette méthode doit être appelée après que le mot de passe a été modifié avec succès.
Pour les sous-classes de
AbstractBaseUser
, le champ mot de passe sera marqué « dirty » lors de l’appel àset_password()
qui déclenche un appel àpassword_changed()
après l’enregistrement de l’utilisateur.
-
password_validators_help_texts
(password_validators=None)[source]¶ Renvoie une liste des textes d’aide de tous les validateurs. Ceux-ci expliquent les exigences du mot de passe aux utilisateurs.
-
password_validators_help_text_html
(password_validators=None)¶ Renvoie une chaîne HTML avec tous les textes d’aide dans une balise
<ul>
. C’est pratique lors de l’ajout de la validation des mots de passe dans les formulaires, car cela permet de passer directement ce contenu au paramètrehelp_text
d’un champ de formulaire.
-
get_password_validators
(validator_config)[source]¶ Renvoie un ensemble d’objets validateurs en fonction du paramètre
validator_config
. Par défaut, toutes les fonctions utilisent les validateurs définis dansAUTH_PASSWORD_VALIDATORS
, mais en appelant cette fonction avec un ensemble différent de validateurs et en passant le résultat dans le paramètrepassword_validators
des autres fonctions, c’est cet ensemble de validateurs qui sera alors utilisé. C’est pratique lorsqu’un certain groupe de validateurs s’applique à la majorité des scénarios, mais qu’il existe certains cas qui demandent un autre ensemble. Si vous utilisez toujours les mêmes validateurs, cette fonction n’est pas utile car la configuration provenant deAUTH_PASSWORD_VALIDATORS
est utilisée par défaut.La structure de
validator_config
est identique à la structure deAUTH_PASSWORD_VALIDATORS
. La valeur renvoyée par cette fonction peut être transmise dans le paramètrepassword_validators
des fonctions présentées précédemment.
Notez que là où le mot de passe est passé en paramètre d’une de ces fonctions, il s’agit toujours du mot de passe en clair, pas de la version hachée.
Écriture de son propre validateur¶
Si les validateurs intégrés à Django ne suffisent pas, vous pouvez écrire votre propre validateur de mot de passe. Les validateurs ont une interface assez restreinte. Elles doivent implémenter deux méthodes :
validate(self, password, user=None)
: valide un mot de passe. RenvoieNone
si le mot de passe est valide, ou génère une erreurValidationError
avec un message d’erreur si le mot de passe n’est pas valide. La méthode doit pouvoir gérer un utilisateuruser
valantNone
; si cela signifie que le validateur ne peut pas s’appliquer, renvoyezNone
pour signifier qu’il n’y a pas d’erreur.get_help_text()
: fournit un texte d’aide pour expliquer les exigences à l’utilisateur.
Tout ce qui est dans OPTIONS
dans AUTH_PASSWORD_VALIDATORS
pour votre validateur sera transmis au constructeur. Tous les paramètres du constructeur doivent posséder une valeur par défaut.
Voici un exemple basique d’un validateur, avec un réglage facultatif :
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
class MinimumLengthValidator:
def __init__(self, min_length=8):
self.min_length = min_length
def validate(self, password, user=None):
if len(password) < self.min_length:
raise ValidationError(
_("This password must contain at least %(min_length)d characters."),
code="password_too_short",
params={"min_length": self.min_length},
)
def get_help_text(self):
return _(
"Your password must contain at least %(min_length)d characters."
% {"min_length": self.min_length}
)
Vous pouvez aussi implémenter password_changed(password, user=None
), qui sera appelée à la suite d’un changement de mot de passe réussi. Cela peut être utilisé pour éviter la réutilisation de mot de passe, par exemple. Cependant, si vous décidez de stocker les mots de passe passés d’un utilisateur, vous ne devriez jamais le faire avec les mots de passe en clair.