• en
  • Langue : fr

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.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
)

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, bcrypt, SHA1, etc. 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 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] ou en téléchargeant la bibliothèque et en l’installant avec python setup.py install.

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

    (Vous devez conserver les autres éléments de la liste, sinon Django ne pourra pas mettre à jour les mots de passe existants ; voir ci-dessous).

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

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.BCryptSHA256PasswordHasher',
        'django.contrib.auth.hashers.BCryptPasswordHasher',
        'django.contrib.auth.hashers.SHA1PasswordHasher',
        'django.contrib.auth.hashers.MD5PasswordHasher',
        'django.contrib.auth.hashers.CryptPasswordHasher',
    )
    

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

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 sont mis à jour lorsque le nombre d’itérations PBKDF2 est modifié.

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). Les algorithmes actuellement pris en charge sont : 'pbkdf2_sha256', 'pbkdf2_sha1', 'bcrypt_sha256' (voir Utilisation de bcrypt avec Django), 'bcrypt', 'sha1', 'md5', 'unsalted_md5' (seulement par rétrocompatibilité) et 'crypt' si la bibliothèque crypt est installée. 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().

Back to Top