Bien sécuriser les mots de passe de sa base de donnée

Un ami m’a demandé il y a quelques mois, quelles pratiques je conseillais en matière de sécurisation d’un compte utilisateur. Il est vrai qu’en ce moment on parle souvent des mots de passe que choisissent les utilisateurs, qui sont sensibles au bruteforce et aux attaques par dictionnaire… C’est bien vrai, mais ça éloigne la responsabilité du développeur de bien sécuriser un mot de passe. Pourtant, cette responsabilité existe. Je ne parlerais pas ici de double authentification, bien que fortement recommandée.

Le risque que l’on va s’efforcer de considérer est celui de l’intrusion par un tiers dans notre base de données. Injection SQL, social engineering, chat qui passe sur le clavier et tape le mot de passe par inadvertance, peu importe, le mal est fait : un méchant s’est enfuit avec un dump de votre base utilisateurs.

Ne pas faire

Déjà, il faut Hasher vos mots de passe dans une base de donnée. (voir le Glossaire, je vais parler tout le long de hashage, pas de cryptage < => chiffrement) Vous avez en effet des obligations légales (auprès de la CNIL) et morales (vis à vis de vos utilisateurs) à le faire.

Comment vérifier un mot de passe ?

Cette question fait bien souvent sourire les développeurs, mais cette logique est la source de beaucoup de mots de passes non sécurisés. En effet, beaucoup de codes récupèrent le mot de passe associé à l’utilisateur dans la base de données pour le comparer au mot de passe entré. En cherchant à décrypter le mot de passe de la base de données.
Le résultat ? De nombreuses bases avec des mots de passes en clair ou chiffrés avec une clef obscure. (D’ailleurs, le sujet de maths de BTS SIO 2013 comportant une question sur le fait de craquer une clef de cryptage)
L’idée est donc de hasher le mot de passe entré, et l’inclure dans la requête SQL qui va se charger de comparer les deux hashs. Si il y a un résultat, c’est bon !

Les algorithmes de hashage « non fiables »

Le plus souvent, vos mot de passe sont hashés en MD5 (RFC 1321). Cet algorithme n’est plus fiable depuis 2004 (déjà !), où une équipe de chercheurs a concrétisée la théorie des collisions dans ces chaînes. De plus, de grandes bases de données existent pour translater du MD5 en clair (Bye bye les mots de passes simples).
Autre algorithme récurrent : le SHA1 (RFC 3174), plus fiable non plus (C’est dommage, ces deux là étaient dans les plus rapides). Plus théorique, des soupçons à propos des collisions héritant de SHA-0 datent d’août 2004. Le SHA1 a donc été mis au placard mais, à ma connaissance, rien de concret n’a été fait.

Le pire, je pense que c’est nos confrères qui développent leurs propres algorithmes de hashage. Pour faire simple : Si vous en faites un rapide et efficace : Vendez le, sinon… Ne le faites pas.
Généralement, de grands mathématiciens s’en chargent, sans vouloir sous estimer mon auditoire, je ne pense pas que ça soit de votre niveau, ni du mien. De toute manière, les fonctions actuelles de PHP sont compilées, et donc plus rapide en exécution (et moins de consommation mémoire) qu’un script PHP interprété.

A faire

Globalement, il faut faire l’inverse de ce qu’il ne fallait pas faire… Ou l’inverse.

Mettre PHP à jour

La librairie Crypt doit être à jour. Je n’ai rien de spéciale à ajouter à ce propos, ça semble logique, c’est pour éviter d’avoir des algorithmes obsolètes qui traînent.

Les algorithmes de hashage « fiables »

Ils sont nombreux ceux là : sha256 et 512, RipeMD, WhirlPool, sha3…
Pas de secrets là encore, tout ça peut changer, et comme pour tout en informatique, il faut rester éveillé sur le sujet. Peut être que le lendemain de la publication de l’article on s’apercevra que le WhirlPool connait une faille.

Le grain de sel

Peu importe l’algorithme choisit, il faut éviter les correspondances de mots de passes (que ce soir un mot de passe identique entre deux utilisateurs qui auraient le même hashage, bien qu’il se trouve que c’était un critère que j’avais retenu y’a quelques années pour détecter les multi-comptes). L’idée est donc de concaténer une chaine autre que le mot de passe avant le hashage.
Certains utilisent des existants enregistrés dans la base de données (Nom d’utilisateur, mail…). Pour ma part je préfère utiliser autre chose : uniqid(), md5 d’un random (dans ce cas précis, on se moque pas mal des possibilités de collision ou autre, on veut juste une chaine aléatoire)… Vous pouvez aussi jeter un oeil à la fonction mcrypt_create_iv().
Je pense que c’est LE POINT à ajouter à vos sécurisations de mots de passe.
Pensez également au cas où le mot de passe est changé, il est préférable que même si le mot de passe est le même qu’avant, le grain de sel soit différent. Ainsi un même mot de passe, pour une même personne, peut avoir une valeur différente dans le temps.

Trop psychoter ne sert à rien par contre, inutile de multiplier les clefs de hashage, à part pour rendre la relecture du code plus complexe…

Glossaire

Il faut faire la différence entre certaines notions…

  • L’identification : Je dis que je suis un panda. Vous êtes obligé de me croire. (Identification par nom d’utilisateur seul)
  • L’authentification : Je dis que je suis un panda, et le prouve, par mes tâches. Je peux très bien les avoir peintes. (Identification par nom d’utilisateur et mot de passe)
  • La certification : Votre ami vous dit que je suis un panda. Pour rester dans l’analogie, vous le croyez, bien qu’on ne sait pas comment il l’a su. (Certification par un tiers)
  • Chiffrement (Cryptage) : On code la chaine de caractères dans le but de la déchiffrer avec une clef, un code, ou autre…
  • Hashage : Gros anglicisme, on créé une empreinte numérique de notre chaine (souvent hexadécimale), qui, en théorie, n’est pas decryptable. La théorie veut que de par ce même fait, deux chaines aient la même empreinte. On parle alors de collision.

Laisser un commentaire


NOTE - Vous pouvez utiliser les éléments et attributs HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" extra="">