Properly Salting Passwords, The Case Against Pepper

Bon, tout le monde devrait le savoir, même si mon expérience récente me montre qu’un rappel n’est pas inutile :

  • On ne stocke pas les mots de passe en clair, on les crypte
  • On n’utilise pas un chiffrement réversible mais une fonction de hachage
  • Un simple hachage ne suffit pas, il faut y ajouter un salage
  • Le salage doit être différent pour chaque mot de passe
  • L’algorithme utilisé doit être lent, comme blowfish par exemple

Croyez moi, j’ai encore découvert il y a peu que non seulement ce n’était pas évident pour tout le monde mais que certains refusent de considérer un simple stockage sous forme md5 sans salage comme une erreur et un problème potentiel de sécurité.

Mais plus que tout ça, pour moi la règle de base c’est « ne jouez pas avec la sécurité ». Si vous n’êtes pas un expert dans la question : ne créez rien et n’implémentez rien vous-même, utilisez des bibliothèques de codes toutes faites.

Et par pitié, ne tentez pas d’améliorer les choses

En jouant sur l’intuition, vous avez toutes les chances d’arriver à un résultat opposé à celui que vous espérez.

Dans le texte du jour à lire, Properly Salting Passwords, The Case Against Pepper, nous avons un superbe exemple que je tente d’expliquer en vain à chaque fois qu’on lève le sujet :

Pour « améliorer » la sécurité, en plus du salage géré par l’algorithme, propre à chaque mot de passe, certains cherchent à ajouter un second salage, global à l’application. L’idée est que le salage présent à côté du mot de passe dans la base de données ne suffit pas, il faudrait en plus connaitre le salage global utilisé par l’applicatif, et donc profiter d’une faille de sécurité plus importante afin d’exploiter quoi que ce soit.

L’idée semble bonne, intuitivement. Malheureusement vous n’êtes probablement pas un expert sur l’algorithme blowfish. Vous ne *savez* pas si ajouter le même salage en début ou en fin du mot de passe avant de l’envoyer à blowfish ne risque pas de réduire la sécurité du résultat. Oh, vous avez probablement l’intuition que ce n’est pas le cas, voire vous en êtes certains, mais aucune documentation de sécurité reconnue comme étant d’autorité ne le précise explicitement.

Vous en êtes à l’intuition et vous avez une chance sur deux de vous planter. Au final, est-ce vraiment un bon pari ? Ça pourrait l’être si l’état de l’art du stockage des mots de passe était franchement insuffisant et s’il n’y avait aucune méthode standard pour l’améliorer. Ici il est probable que vous ne soyez pas encore à l’état de l’art (n’utiliseriez-vous pas sha1 ou md5 ?) et cet état de l’art est probablement suffisant si vous utilisez suffisamment d’itérations.

Mais plus que cette question du double salage, qui est une mauvaise idée pour ce que vous et moi en savons, c’est toute l’implémentation que vous ne devriez pas toucher. Utilisez une bibliothèque de code éprouvée, ou mieux : une fonction prévue pour. En PHP nous avons « crypt », qui avec avec l’algorithme blowfish et suffisamment d’itérations, rendra votre stockage des mots de passe bien plus solide que tout le reste de votre application.

7 réflexions sur “ Properly Salting Passwords, The Case Against Pepper ”

  1. Je le mets en commentaire afin d’en diminuer l’impact : Oui, il est extrêmement probable que ce double salage aurait amélioré la sécurité (ou du moins ne l’aurait pas diminué), et encore plus probable si l’insertion du sel est faite avec un XOR ou procédé similaire et non une concaténation en début ou fin de mot de passe.

    Tout le fond de du billet et de l’article lié est dans ce terme. « Probable », même quand on y accole « extrêmement », c’est peu rassurant en sécurité.

  2. Petit détail sur l’implémentation de base de PHP, via crypt(): elle demande de générer son propre salt soi-même. Ça pose des problèmes de sécu sympa, vu que personne ne sait générer un salt correctement :-)

    Il existe 2/3 librairies qui le font bien, mais sinon, grosso modo, il faut utiliser openssl_random_pseudo_bytes() qui est fait pour ça.

    1. Bof, le salt l’important est qu’il soit raisonnablement distribué dans la base et que le salt ne dépende pas trop directement du mot de passe en clair.

      Une génération aléatoire très moyenne suffit à priori puisque l’unique objectif est de casser les rainbow table (ou alors il me manque un type d’attaque).

      Maintenant oui, si crypt() est déjà un niveau au dessus des fonctions de base, utiliser une lib plus haut niveau ce n’est pas mal.

      1. Le salt (par password) ne sert pas juste contres les attaques de type Rainbow Table: il sert aussi à empêcher un attaquant qui a déchiffré une entrée de ta base de déchiffrer les passwords identiques à celui la.

        Tu peux imaginer des attaques rigolotes ou un attaquant qui aurait accès à ta base, conscient de la faiblesse de ton algo de génération de salt, arrive à te forcer à utiliser le salt qu’il veut (par exemple, si ton random dépend juste du temps) et donc arrive à te faire pré-générer des hash en utilisant *ta* puissance CPU.

        En fait, en partant de cette hypothèse que le salt n’a besoin que d’être moyennement aléatoire, tu es en train de tomber dans le même travers que tu dénonces (désolé pour la formule choc): intuitivement, ça n’a pas l’air grave, mais en fait, ça l’est :)

        Les « bonnes » lib gérant ce genre de problématiques ne laissent pas le développeur gérer le salt lui-même.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>