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 l’installation de Django peut prendre en charge. La première occurrence de cette liste (c’est-à-dire settings.PASSWORD_HASHERS[0]) sera utilisée pour stocker les mots de passe et toutes les autres occurrences correspondent à des méthodes de hachage valides pouvant être utilisées pour vérifier des mots de passe existants. Cela signifie que si vous souhaitez utiliser un algorithme différent, il faudra modifier PASSWORD_HASHERS afin que votre algorithme préféré figure en premier dans la liste.

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.BCryptPasswordHasher',
]

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

New in Django 1.10.

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.

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 Argon2 comme algorithme de stockage par défaut, faites ceci :

  1. Installez la bibliothèque argon2-cffi. Cela peut se faire en lançant pip install django[argon2], ce qui est équivalent à pip install argon2-cffi (en installant aussi toute version de paquet exigée par le fichier setup.py de Django).

  2. Modifiez PASSWORD_HASHERS pour que Argon2PasswordHasher 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.BCryptPasswordHasher',
    ]
    

    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 :

  1. Installez la bibliothèque bcrypt. Cela peut se faire en lançant pip install django[bcrypt], ce qui est équivalent à pip install bcrypt (en installant aussi toute version de paquet exigée par le fichier setup.py de Django).

  2. Modifiez PASSWORD_HASHERS pour que BCryptSHA256PasswordHasher 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.BCryptPasswordHasher',
        'django.contrib.auth.hashers.PBKDF2PasswordHasher',
        'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
        'django.contrib.auth.hashers.Argon2PasswordHasher',
    ]
    

    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.

Troncature de mot de passe avec

Les concepteurs de bcrypt tronquent tous les mots de passe à 72 caractères, ce qui signifie que bcrypt(motdepasse_de_100_caracteres) == bcrypt(motdepasse_de_100_caracteres[:72]). La classe BCryptPasswordHasher originale n’effectue pas d’opération particulière et est donc également sujet à cette limite cachée de longueur de mot de passe. BCryptSHA256PasswordHasher corrige cela en hachant préalablement le mot de passe avec sha256. Ceci empêche que le mot de passe soit tronqué et cette classe devrait donc être privilégiée. La conséquence pratique de cette troncature est très marginale dans la mesure où la longueur moyenne des mots de passe est bien en-dessous de 72 caractères et que même avec cette limite de 72 caractères, la puissance de calcul nécessaire pour casser une telle empreinte bcrypt par force brute dans un temps raisonnable est encore astronomique. Néanmoins, nous vous recommandons d’utiliser BCryptSHA256PasswordHasher de toute façon sur le principe de « deux précautions valent mieux qu’une ».

Autres implémentations de bcrypt

Il existe plusieurs autres implémentations permettant d’utiliser bcrypt avec Django. La prise en charge de bcrypt par Django n’est PAS directement compatible avec ces variantes. Pour utiliser l’une de ces variantes, vous devrez modifier les empreintes dans votre base de données pour qu’elles correspondent à la forme bcrypt$(sortie bcrypt brute). Par exemple : bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy.

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. Par exemple, pour augmenter le nombre d’itérations utilisé par l’algorithme par défaut PBKDF2 :

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

  2. 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.BCryptPasswordHasher',
    ]
    

Et voilà, votre installation Django utilise dorénavant plus d’itérations lorsqu’elle stockera les mots de passe avec PBKDF2.

Argon2

Argon2 possède trois attributs qui peuvent être personnalisés :

  1. time_cost contrôle le nombre d’itérations pour l’empreinte.

  2. memory_cost contrôle la taille mémoire utilisée lors du calcul de l’empreinte.

  3. 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 :

  1. Définissez parallelism au nombre de fils d’exécution à exploiter pour le calcul de l’empreinte.

  2. Définissez memory_cost au nombre de Kio de mémoire à exploiter.

  3. Ajustez time_cost et mesurez le temps passé à hacher un mot de passe. Choisissez une valeur time_cost qui consomme un temps acceptable pour vous. Si time_cost défini à 1 est encore trop lent, baissez la valeur memory_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.

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 ou de tours bcrypt 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.

Changed in Django 1.9:

La mise à jour des mots de passe lors du changement du nombre de tours bcrypt a été ajoutée.

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 ou SHA1, 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 SHA1 afin qu’elles utilisent PBKDF2(SHA1(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é :

accounts/hashers.py
from django.contrib.auth.hashers import (
    PBKDF2PasswordHasher, SHA1PasswordHasher,
)


class PBKDF2WrappedSHA1PasswordHasher(PBKDF2PasswordHasher):
    algorithm = 'pbkdf2_wrapped_sha1'

    def encode_sha1_hash(self, sha1_hash, salt, iterations=None):
        return super(PBKDF2WrappedSHA1PasswordHasher, self).encode(sha1_hash, salt, iterations)

    def encode(self, password, salt, iterations=None):
        _, _, sha1_hash = SHA1PasswordHasher().encode(password, salt).split('$', 2)
        return self.encode_sha1_hash(sha1_hash, salt, iterations)

La migration de données pourrait ressembler à ceci :

accounts/migrations/0002_migrate_sha1_passwords.py
from django.db import migrations

from ..hashers import PBKDF2WrappedSHA1PasswordHasher


def forwards_func(apps, schema_editor):
    User = apps.get_model('auth', 'User')
    users = User.objects.filter(password__startswith='sha1$')
    hasher = PBKDF2WrappedSHA1PasswordHasher()
    for user in users:
        algorithm, salt, sha1_hash = user.password.split('$', 2)
        user.password = hasher.encode_sha1_hash(sha1_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:

mysite/settings.py
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'accounts.hashers.PBKDF2WrappedSHA1PasswordHasher',
]

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.SHA1PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher',
    'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
]

Les noms d’algorithmes correspondants sont :

  • pbkdf2_sha256
  • pbkdf2_sha1
  • argon2
  • bcrypt_sha256
  • bcrypt
  • sha1
  • md5
  • unsalted_sha1
  • unsalted_md5
  • crypt

Écriture de son propre algorithme de hachage

New in Django 1.9.3.

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.

check_password(password, encoded)[source]

Si vous avez besoin d’authentifier manuellement un utilisateur en comparant un mot de passe en clair avec l’empreinte de ce mot de passe en base de données, utilisez la fonction utilitaire check_password(). Elle accepte deux paramètres : le mot de passe en clair à contrôler et la valeur complète du champ password d’un utilisateur en base de données comme valeur de comparaison ; la fonction renvoie True si les valeurs correspondent, sinon False.

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. 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 vaut None, un mot de passe inutilisable est renvoyé (un mot de passe qui fera que check_password() renvoie toujours False) .

is_password_usable(encoded_password)[source]

Vérifie que la chaîne indiquée est une empreinte de mot de passe qui a une chance d’être validée par check_password().

Validation des mots de passe

New in Django 1.9.

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 il est facile d’écrire ses propres validateurs.

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 recevoir les mots de passe qui ont été changés. 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 minimal 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 simplement 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 1000 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 simplement 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.

Il est possible de définir le degré de similitude admis avant que le mot de passe ne soit rejeté avec le paramètre max_similarity sur une échelle de 0 à 1. Une valeur de 0 causera le rejet de tous les mots de passe, alors qu’une valeur de 1 ne rejettera que les mots de passe qui sont identiques à l’une des valeurs 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. Par défaut, la vérification se fait avec une list de 1000 mots de passe courants créée par Mark Burnett.

password_list_path peut contenir un chemin vers un fichier personnalisé de mots de passe courants. Ce fichier doit contenir un mot de passe par ligne et peut être soit compressé gzip, soit du texte pur.

class NumericPasswordValidator[source]

Vérifie que le mot de passe n’est pas entièrement numérique.

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 exception ValidationError 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ètre help_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 dans AUTH_PASSWORD_VALIDATORS, mais en appelant cette fonction avec un ensemble différent de validateurs et en passant le résultat dans le paramètre password_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 de AUTH_PASSWORD_VALIDATORS est utilisée par défaut.

La structure de validator_config est identique à la structure de AUTH_PASSWORD_VALIDATORS. La valeur renvoyée par cette fonction peut être transmise dans le paramètre password_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 sont des classes relativement simples. Elles doivent implémenter deux méthodes :

  • validate(self, password, user=None): valide un mot de passe. Renvoie None si le mot de passe est valide, ou génère une erreur ValidationError avec un message d’erreur si le mot de passe n’est pas valide. La méthode doit pouvoir gérer un utilisateur user valant None; si cela signifie que le validateur ne peut pas s’appliquer, renvoyez simplement None 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 ugettext as _

class MinimumLengthValidator(object):
    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.

Back to Top