Une des questions qu'un développeur php débutant se pose lorsque l'on lui conseille d'encoder des mots de passe en md5, c'est comment décoder un md5.
Le problème c'est que contrairement à une fonction de cryptage, l'algorithme du md5 a pour but de créer un hash de la chaine passée en paramètre. Il n'est donc pas possible de trouver une fonction inverse du md5 qui permettrait de décoder le md5.
Utilisation du md5 dans les mots de passe
On utilise souvent le md5 pour stocker les mots de passe dans un système d'informations (une base de données par exemple).
L'intérêt de stocker le md5 du mot de passe dans la base de données et que le mot de passe original n'est pas visible que ce soit pour l'administrateur ou pour un "pirate" qui passerait par là.
Comparaison des mots de passe sous forme de md5
Ce qu'il faut bien comprendre c'est que le mot de passe original n'est connu que par l'utilisateur détenteur du compte protégé par mot de passe. Pour savoir si l'utilisateur a saisi le bon mot de passe il faut donc comparer les md5.
D'une part on a le md5 stocké en base de données et de l'autre on calcul le md5 du mot de passe saisi par l'utilisateur comme le montre l'exemple suivant :
Formulaire de login
<form method="post" action="login.php">
<table cellspacing="0" cellspacing="0">
<tr>
<th>Email</th><td><input type="text" name="email"/></td>
</tr>
<tr>
<th>Mot de passe</th><td><input type="password" name="password"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Se connecter" class="submit"/></td>
</tr>
</table>
</form>
Transaction de login
<?php
/*On recupére l'email du fomulaire de login*/
$email = isset($_POST['email']) ? $_POST['email'] : '';
/*On recupére le mot de passe*/
$pass = isset($_POST['password']) ? md5($_POST['password']) : '';
/*On recupére l'instance de la base de données*/
$db = Database::getInstance();
/*On protège les données entrées par l'utilisateur pour eviter les injections*/
$db->bind('EMAIL',$email);
$db->bind('PASS',$pass);
/*On cherche en base de donnée un utilisateur qui a un email et un mot de passe qui correspondent*/
$user = $db->select('SELECT USR_ID FROM USERS WHERE EMAIL=:EMAIL AND PASS=:PASS LIMIT 1');
/**On a trouvé c'est bon*/
if(isset($user[0]['USR_ID']))
{
echo 'connecté';
}
/**On a pas trouvé c'est pas bon*/
else
{
echo 'non connecté';
}
?>
Sécurité et md5
Dans cet exemple on voit donc que le md5 est un moyen simple de sécurisé des mots de passe.
Pourtant le md5 en lui même n'est pas très sécurisé car il existe des dictionnaires de md5 (gdataonline) qui permettent de trouver un mot de passe à partir de son md5. Par exemple ab4f63f9ac65152575886860dde480a1 correspond au md5 de azerty.
Beaucoup vous conseillerons de remplacer la fonction md5 par la fonction sha1, mais des dictionnaires sha1 existent aussi. La solution la plus simple pour éviter ces attaques par dictionnaire est de concaténer une chaine avec le mot de passe avant de calculer le md5.
Fonction de calcul de md5 contre les attaques par dictionnaire
<?php
/**
* Retourne un md5 qui est indécriptable par les dictionnaires
*
* @author petitchevalroux
* @see http://petitchevalroux.net
* @param unknown_type $string
* @return string
*/
function betterMd5($string)
{
static $magicword = 'ma super chaine anti attaque par dictionnaire';
return md5($magicword.$string);
}
?>
Cette fonction est à utiliser lors de l'enregistrement du mot de passe dans la base de données et lors de la comparaison dans la transaction de login.
Ne modifiez pas votre chaine magique une fois que vous l'avez utilisée pour enregistrer des mots de passe car sinon ceux ci ne correspondront plus et vos utilisateurs ne pourront plus se connecter.
Image : bohman