Hash, sécurité & MySQL

novembre 11, 2008

Une fonction de hash est une fonction qui prend une chaîne de caractères en entrée et qui renvoi une autre chaine de caractères. La chaîne de caractères résultat a toujours la même longueur et est strictement identique pour une même entrée.

Une des utilisations du hashage sert a masquer les mots de passes stockés dans une table.

Au lieu d’avoir une table utilisateur, faiblement sécurisée avec un mot de passe en clair:

+----------+------------------------+
| name     | password_en_clair      |
+----------+------------------------+
| freshdaz | mot_de_passe           |
+----------+------------------------+

Il est préférable d’avoir ceci, le même mot de passe mais hashé:

+----------+---------------------------------------+
| name     | password_hash                         |
+----------+---------------------------------------+
| freshdaz | 8b70bf2ffce34ced3223dfc9e4fa9cc7      |
+----------+---------------------------------------+

Comme vous pouvez le constater le mot de passe hashé est plus difficile à lire, d’autant plus que le hash est (sensé être) irréversible (en fait tout est une question de temps).

MySQL propose 5 fonctions de hashage:

CRC : (contrôle de redondance cyclique)

c’est une méthode pour contrôler l’intégrité des données, donc hors sujet 🙂

mysql> SELECT crc32('mot_de_passe');
+-----------------------+
| crc32('mot_de_passe') |
+-----------------------+
|             965676113 |
+-----------------------+

MD5 : (Message Digest 5)

très populaire mais n’est donc plus considéré comme sûr au sens cryptographique. Autrement dit, une petite recherche sur le net et vous trouverez facilement des algorithmes pour le cracker.

mysql> SELECT md5('mot_de_passe');
+----------------------------------+
| md5('mot_de_passe')              |
+----------------------------------+
| 8b70bf2ffce34ced3223dfc9e4fa9cc7 |
+----------------------------------+

SHA1 : (Secure Hash Algorithm )

Conçue par la National Security Agency (NSA) (est-ce une bonne nouvelle ?) 😀

Plus sécurisé que le md5.

mysql> SELECT sha1('mot_de_passe');
+------------------------------------------+
| sha1('mot_de_passe')                     |
+------------------------------------------+
| d10c988ca61b785f5a7756b5852683d798fe4d92 |
+------------------------------------------+

PASSWORD:

Algorithme « maison » de MySQL. Utilisé pour stocker les mots de passes des utilisateurs du serveur MySQL.

mysql> SELECT password('mot_de_passe');
+-------------------------------------------+
| password('mot_de_passe')                  |
+-------------------------------------------+
| *C3D87F1C2FADE3F03484FC62E669276C2A37266F |
+-------------------------------------------+

OLD_PASSWORD :

Ancien algorithme pour stocker les mot de passes des utilisateurs du serveur MySQL. Utilisé jusqu’à la version 4.0.x de MySQL. Il a été changé lui aussi pour des raison de sécurité. Là encore vous trouverez très facilement le nécessaire pour le cracker.

mysql> SELECT old_password('mot_de_passe');
+------------------------------+
| old_password('mot_de_passe') |
+------------------------------+
| 684ec7590a2271b0             |
+------------------------------+

Quelles fonctions utiliser ?

Comme souvent en informatique, il faut faire un compromis entre meilleurs performances et sécurité optimale. En d’autre terme un sha1 plus sécurisé qu’un md5 mettra cependant plus de temps pour hasher une même chaine de caractères.

Vérifions tout ceci:

mysql> SELECT md5('olivierdasini');
+----------------------------------+
| md5('olivierdasini')             |
+----------------------------------+
| a42bc0139343fc758a414f70eda6f209 |
+----------------------------------+
1 row in set (0.00 sec)

mysql> SELECT sha1('olivierdasini');
+------------------------------------------+
| sha1('olivierdasini')                    |
+------------------------------------------+
| f2cdbfdf62d717ab96528235a1b1ff34671860d4 |
+------------------------------------------+
1 row in set (0.00 sec)

hum, hum pas très probant…

Aidons nous de la fonction benchmark():

mysql> SELECT benchmark(3000000,md5('olivierdasini'));
+-----------------------------------------+
| BENCHMARK(3000000,md5('olivierdasini')) |
+-----------------------------------------+
|                                       0 |
+-----------------------------------------+
1 row in set (12.27 sec)

mysql> SELECT benchmark(3000000,sha1('olivierdasini'));
+------------------------------------------+
| BENCHMARK(3000000,sha1('olivierdasini')) |
+------------------------------------------+
|                                        0 |
+------------------------------------------+
1 row in set (15.91 sec)

En exécutant ces 2 fonctions plusieurs fois, (grâce à benchmark()) on s’aperçoit qu’il faut environ 25% de temps supplémentaire pour l’algorithme sha1 que pour le md5. Ce qui est loin d’être négligeable.

Regardons comment se débrouillent les fonctions « maison » de MySQL:

mysql> SELECT benchmark(3000000,password('olivierdasini'));
+----------------------------------------------+
| BENCHMARK(3000000,password('olivierdasini')) |
+----------------------------------------------+
|                                            0 |
+----------------------------------------------+
1 row in set (7.24 sec)

17:08 root$test> SELECT benchmark(3000000,old_password('olivierdasini'));
+--------------------------------------------------+
| BENCHMARK(3000000,old_password('olivierdasini')) |
+--------------------------------------------------+
|                                                0 |
+--------------------------------------------------+
1 row in set (4.26 sec)

Le verdict est sans appels, avec ses 7 secondes (près de 50% de temps en moins que md5 ), la fonction password() est d’un bon rapport performance sécurité. Pour rappel, c’est cette fonction qu’utilise le serveur MySQL pour gérer les mots de passes de ses comptes utilisateurs. Inconvénient non négligeable, elle est spécifique (à ma connaissance) à MySQL (mais est-ce vraiment un inconvénient ?  🙂 ).

Quant à l’ancienne façon de hasher les mots de passes, elle est évidement très performante, mais on a vu que niveau sécurité, elle laisse à désirer…

Les fonctions présentées sont une bonne solution pour sécuriser ses mots de passes. Il est néanmoins possible d’augmenter encore un peu plus le niveau de sécurité. Une des techniques consiste à renforcer le mot de passe utilisateur en lui rajoutant une chaine de caractères et en combinant plusieurs algorithmes de hashage.

Par exemple, avec comme mot de passe: olivierdasini, on peut concaténer, avec la fonction concat(), la date de naissance: 121174_ et combiner différents algorithmes:

mysql> SELECT benchmark(3000000,md5(concat(sha1('121174_'), 'olivierdasini')));
+------------------------------------------------------------------+
| benchmark(3000000,md5(concat(sha1('121174_'), 'olivierdasini'))) |
+------------------------------------------------------------------+
|                                                                0 |
+------------------------------------------------------------------+
1 row in set (29.30 sec)
mysql> SELECT benchmark(3000000,password(concat(old_password('121174_'), 'olivierdasini')));
+-------------------------------------------------------------------------------+
| benchmark(3000000,password(concat(old_password('121174_'), 'olivierdasini'))) |
+-------------------------------------------------------------------------------+
|                                                                             0 |
+-------------------------------------------------------------------------------+
1 row in set (12.06 sec)

Avec de telles combinaisons, vos mots de passes sont plus à l’abri, par contre les temps de hashage sont doublés. Comme ont le disait précédemment, tout est une histoire de compromis.

Comments are closed.