PHP Australia Conference 2015

Hashage de mots de passe sûr

Cette section explique les raisons d'utiliser des fonctions de hashage pour les mots de passe, ainsi que la façon de le faire efficacement.

Pourquoi devrais-je hasher les mots de passe envoyés par les utilisateurs de mon application ?

Le hashage de mot de passe est l'une des pratiques de sécurité les plus basiques qui doit être effectuée. Sans cela, chaque mot de passe stocké peut être volé si le support de stockage (typiquement une base de données) est compromis. Ce mot de passe peut alors être immédiatement utilisé pour accèder frauduleusement non seulement à votre application mais aussi sur d'autres applications si l'utilisateur utilise le même mot de passe ailleurs.

En appliquant un hashage sur le mot de passe avant de le stocker, vous rendez la tâche d'un attaquant très difficile pour connaitre le mot de passe original, et vous avez toujours la possibilité de comparer le mot de passe hashé à une chaîne reçue.

Il est important de noter que le hashage ne fait que protéger les mots de passe dans la base, pas leur éventuelle interception alors qu'ils sont envoyés à l'application par l'utilisateur, via du code malicieux injecté dans l'application, par exemple.

Pourquoi les fonctions traditionnelles de hashage comme md5() et sha1() sont-elles inappropriées aux mots de passe ?

Les algorithmes de hashage comme MD5, SHA1 et SHA256 sont destinés à être rapides et efficaces. Avec les équipements informatiques modernes, il est devenu facile d'attaquer par force brute la sortie de ces algorithmes pour retrouver la chaîne originale.

C'est la raison pour laquelle de nombreux experts en sécurité considèrent ces algorithmes comme faibles et les déconseillent fortement pour hasher un mot de passe utilisateur.

Alors, comment hasher mes mots de passe ?

Lorsqu'on hashe des mots de passe, les deux considérations les plus importantes sont le temps de traitement, et le grain de sel. Plus la puissance de traitement requise est élevée, plus il faudra du temps pour casser le mot de passe en analysant sa sortie.

PHP 5.5 fournit une API native de hashage de mot de passe qui gère à la fois le hashage et la vérification de mots de passe, le tout, de manière totalement sécurisée. Il existe aussi une » bibliothèque pure PHP de compatibilité pour PHP 5.3.7 et suivants.

Une autre option est la fonction crypt(), qui supporte différents algorithmes de hashage en PHP 5.3 et suivants. Lors de l'utilisation de cette fonction, vous avez la garantie que l'algorithme sélectionné est disponible, sachant que PHP contient une implémentation native de chaque algorithme supporté, dans le cas où un ou plusieurs algorithmes n'est pas supporté par votre système.

L'algorithme suggéré à utiliser pour le hashage de mots de passe est Blowfish, qui est aussi l'algorithme par défaut de l'API de hashage de mots de passe, sachant qu'il est significativement plus gourmand en calcul que MD5 ou SHA1, mais plus évolutif.

Notez que si vous utilisez la fonction crypt() pour vérifier un mot de passe, vous devez faire attention aux attaques de synchronisation, en utilisant une constante de temps pour la comparaison. Ni les opérateurs == et === ni la fonction strcmp() n'effectuent de comparaisons en utilisant des constantes de temps. Sachant que la fonction password_verify() le fera pour vous, vous êtes vivement encouragé à utiliser l'API native de hashage de mots de passe lorsque vous le pouvez.

Qu'est ce que le grain de sel ?

Un grain de sel, ou "salt", en cryptographie, est appliqué durant le processus de hashage pour éliminer la possibilité d'attaques par dictionnaires (hashages enregistrés dans une grande liste et comparés).

En d'autres termes, un grain de sel est une petite donnée additionnelle qui renforce significativement la puissance du hashage pour le rendre beaucoup plus difficile à cracker. Il existe de nombreux services en ligne qui proposent de volumineux dictionnaires de mots de passe avec leur hash. L'utilisation d'un grain de sel rend ces dictionnaires inutiles.

password_hash() va créer un salt aléatoire si vous n'en fournissez pas, et c'est généralement la façon la plus sécurisé et la plus simple.

Comment stocker mes salts ?

Lors de l'utilisation de la fonction password_hash() ou de la fonction crypt(), la valeur retournée inclue le salt comme parti du hash généré. Cette valeur devrait être stockée telle quelle dans votre base de données, sachant qu'elle inclue les informations sur la fonction de hashage utilisée et peut donc être fournie directement à la fonction password_verify() ou la fonction crypt() lors de la vérification des mots de passe.

Le diagramme suivant montre le format d'une valeur retournée de la fonction crypt() ou password_hash(). Comme vous pouvez le voir, tout est présent, comme toutes les informations sur l'algorithme et le salt nécessaires pour une future vérification de mots de passe.


        Les composants de la valeur retournée par la fonction password_hash et crypt :
        dans l'ordre, l'algorithme choisi, les options de l'algorithme, le salt utilisé,
        et le mot de passe hashé.

add a note add a note

User Contributed Notes 6 notes

up
22
alf dot henrik at ascdevel dot com
6 months ago
I feel like I should comment some of the clams being posted as replies here.

For starters, speed IS an issue with MD5 in particular and also SHA1. I've written my own MD5 bruteforce application just for the fun of it, and using only my CPU I can easily check a hash against about 200mill. hash per second. The main reason for this speed is that you for most attempts can bypass 19 out of 64 steps in the algorithm. For longer input (> 16 characters) it won't apply, but I'm sure there's some ways around it.

If you search online you'll see people claiming to be able to check against billions of hashes per second using GPUs. I wouldn't be surprised if it's possible to reach 100 billion per second on a single computer alone these days, and it's only going to get worse. It would require a watt monster with 4 dual high-end GPUs or something, but still possible.

Here's why 100 billion per second is an issue:
Assume most passwords contain a selection of 96 characters. A password with 8 characters would then have 96^8 = 7,21389578984e+15 combinations.
With 100 billion per second it would then take 7,21389578984e+15 / 3600 = ~20 hours to figure out what it actually says. Keep in mind that you'll need to add the numbers for 1-7 characters as well. 20 hours is not a lot if you want to target a single user.

So on essence:
There's a reason why newer hash algorithms are specifically designed not to be easily implemented on GPUs.

Oh, and I can see there's someone mentioning MD5 and rainbow tables. If you read the numbers here, I hope you realize how incredibly stupid and useless rainbow tables have become in terms of MD5. Unless the input to MD5 is really huge, you're just not going to be able to compete with GPUs here. By the time a storage media is able to produce far beyond 3TB/s, the CPUs and GPUs will have reached much higher speeds.

As for SHA1, my belief is that it's about a third slower than MD5. I can't verify this myself, but it seems to be the case judging the numbers presented for MD5 and SHA1. The issue with speeds is basically very much the same here as well.

The moral here:
Please do as told. Don't every use MD5 and SHA1 for hasing passwords ever again. We all know passwords aren't going to be that long for most people, and that's a major disadvantage. Adding long salts will help for sure, but unless you want to add some hundred bytes of salt, there's going to be fast bruteforce applications out there ready to reverse engineer your passwords or your users' passwords.
up
9
fluffy at beesbuzz dot biz
2 years ago
The security issue with simple hashing (md5 et al) isn't really the speed, so much as the fact that it's idempotent; two different people with the same password will have the same hash, and so if one person's hash is brute-forced, the other one will as well.  This facilitates rainbow attacks.  Simply slowing the hash down isn't a very useful tactic for improving security.  It doesn't matter how slow and cumbersome your hash algorithm is - as soon as someone has a weak password that's in a dictionary, EVERYONE with that weak password is vulnerable.

Also, hash algorithms such as md5 are for the purpose of generating a digest and checking if two things are probably the same as each other; they are not intended to be impossible to generate a collision for.  Even if an underlying password itself requires a lot of brute forcing to determine, that doesn't mean it will be impossible to find some other bit pattern that generates the same hash in a trivial amount of time.

As such: please, please, PLEASE only use salted hashes for password storage.  There is no reason to implement your own salted hash mechanism, either, as crypt() already does an excellent job of this.
up
2
loveun1x at yahooc dot om
10 months ago
The section "Why are common hashing functions such as md5() and sha1() unsuitable for passwords?" is completely wrong. No one says MD5 and SHA-1 aren't suitable for password hashing due to their speed. (MD5 is broken for digital signatures but not yet for password hashing, but not because it is fast.) A single round of them is unsuitable, but that is not a problem with the underlying algorithms themselves.

Always use a salt, preferably a big (e.g. at least 16 characters) salt. Always run through multiple rounds of of the hashing. Most implementations today use several tens of thousands or hundreds of thousands of rounds, for example 7-zip's encrypted format uses 262,144 rounds of SHA-256.
up
4
sgbeal at googlemail dot com
2 years ago
sha1 in conjunction with one or more salt values need not be as insecure as the above makes it out to be. e.g. the Fossil SCM creates an sha1 password hash based on a user's clear-text password combined with the user's name and a shared secret known only to the specific source repository for which the user is set up.
up
-15
user at wample dot com
6 months ago
password hashing may be better with the use of "phpass"
up
-38
owlstead
1 year ago
Clearly you should by now use PBKDF2, bcrypt or scrypt to store secure "hashes" of passwords. Unfortunately the PHP crypto implementations and documentation keeps propagating insecure protocols and algorithms. Isn't there a single PHP programmer that could clean up the cryptographic functions and libraries?
To Top