Si votre site permet aux visiteurs de s'enregistrer et de se connecter, vous allez devoir gérer des mots de passe
Cette donnée est l'une des plus sensibles que vous pourriez avoir à stocker (avec les coordonnées bancaires)
Il est nécessaire de respecter un minimum de sécurité
Nous allons simuler une connexion classique à un site avec email et mot de passe
Inscription / Login
Inscription
(Sans validation par email)
Login
Lorsque vous renvoyer une erreur, ne donnez pas trop d'information
Nous allons nous baser sur une base de données simple
Créer une base de données et executer la requête SQL suivante
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(250) NOT NULL,
`password` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
Nous n'allons pas voir la partie formulaire.
Admettons que les données soient envoyées en POST et qu'elles n'aient pas besoin d'être vérifiées
Le code d'inscription ressemblerait à ça
// Retrieve inputs
$email = $_POST['email'];
$password = $_POST['password'];
// SQL query
$prepare = $pdo->prepare('INSERT INTO users (email,password) VALUES (:email,:password)');
$prepare->bindValue(':email',$email);
$prepare->bindValue(':password',$password);
$exec = $prepare->execute();
Et le code de login ressemblerait à ça
// Retrieve inputs
$email = $_POST['email'];
$password = $_POST['password'];
// SQL query
$prepare = $pdo->prepare('SELECT * FROM users WHERE email = :email LIMIT 1');
$prepare->bindValue(':email',$email);
$query = $prepare->execute();
$user = $prepare->fetch();
// Test password
if($user->password == $password)
echo 'You shall pass';
else
echo 'You shall not pass';
Ici, le mot de passe est sauvegardé en clair
N'importe quel individu ayant accès à la base de données (administrateur ou hacker) pourra voir le mot de passe de chaque utilisateur
La solution consiste à hasher le mot de passe pour le rendre méconnaissable
Pour cela nous allons utiliser la fonction hash()
echo hash('sha256','monmotdepasse');
// Ce qui affichera
// a7af71ad2b0ce07c36781ab7c8a6d36bd703824c22647f85d6de62063b219bc6
Un même algorithme avec une même chaîne de caractères renvera toujours le même résultat
echo hash('sha256','azerty'); // f2d81a260dea8a100dd517984e53c56a7523d96942a834b9cdc249bd4e8c7aa9
echo hash('sha256','azerty'); // f2d81a260dea8a100dd517984e53c56a7523d96942a834b9cdc249bd4e8c7aa9
echo hash('sha256','azerty'); // f2d81a260dea8a100dd517984e53c56a7523d96942a834b9cdc249bd4e8c7aa9
echo hash('sha256','azerty'); // f2d81a260dea8a100dd517984e53c56a7523d96942a834b9cdc249bd4e8c7aa9
Il existe de nombreux algorithmes de hash
Certains sont lents, certains peuvent être décryptés (md5)
SHA-256 est rapide, n'a jamais été décrypté et est très populaire
Notre code d'inscription deviendra donc
// Retrieve inputs
$email = $_POST['email'];
$password = hash('sha256',$_POST['password']); // Hash
// SQL query
$prepare = $pdo->prepare('INSERT INTO users (email,password) VALUES (:email,:password)');
$prepare->bindValue('email',$email);
$prepare->bindValue('password',$password);
$prepare->execute();
Notre code de login deviendra donc
// Retrieve inputs
$email = $_POST['email'];
$password = hash('sha256',$_POST['password']); // Hash
// SQL query
$prepare = $pdo->prepare('SELECT * FROM users WHERE email = :email LIMIT 1');
$prepare->bindValue('email',$email);
$prepare->execute();
$user = $prepare->fetch();
// Test password
if($user->password == $password)
echo 'You shall pass !';
else
echo 'You shall not pass !';
Hasher, c'est pas mal, mais insuffisant
Une rainbow table contient une grande quantité de mots de passes "classiques" et leurs versions hashés
Si le visiteur a utilisé un de ces mots de passe, il sera facile de le retrouver dans la rainbow table à partir de la version encryptée
Rajouter quelques caractères au mot de passe pour être certain qu'il n'existe pas dans les rainbow tables
Le mot de passe azerty deviendra par exemple 76t!"ed#azerty
Cette technique s'appelle le salage (salt)
Notre code d'inscription deviendra donc
// Retrieve inputs
$email = $_POST['email'];
$password = hash('sha256',SALT.$_POST['password']); // Hash + Salt
// SQL query
$prepare = $pdo->prepare('INSERT INTO users (email,password) VALUES (:email,:password)');
$prepare->bindValue('email',$email);
$prepare->bindValue('password',$password);
$prepare->execute();
Notre code de login deviendra donc
// Retrieve inputs
$email = $_POST['email'];
$password = hash('sha256',SALT.$_POST['password']); // Hash + Salt
// SQL query
$prepare = $pdo->prepare('SELECT * FROM users WHERE email = :email LIMIT 1');
$prepare->bindValue('email',$email);
$prepare->execute();
$user = $prepare->fetch();
// Test password
if($user->password == $password)
echo 'You shall pass !';
else
echo 'You shall not pass !';
Il s'agit du minimum pour stocker des mots de passes
Il existe bien d'autres méthodes et le salt peut être amélioré
(salt unique par ligne dans la BDD)
Si vous travaillez sur un projet et constatez que les mots de passes sont stockés en clair, corrigez le problème ou avertissez le responsable.
Aller plus loin :
http://www.sitepoint.com/password-hashing-in-php/ http://code.tutsplus.com/tutorials/understanding-hash-func...