158 lines
4.8 KiB
JavaScript
158 lines
4.8 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const crypto = require('crypto'); // Natif à Node.js
|
|
const argon2 = require('argon2'); // Bibliothèque installée
|
|
|
|
/* Simulation d'une base de données utilisateurs.
|
|
Dans une vraie app, on utiliserait MongoDB, MySQL, PostgreSQL, etc.
|
|
On la place ici pour que la démo soit auto-contenue.
|
|
*/
|
|
const fakeDatabase = {};
|
|
|
|
/*
|
|
==================================================================
|
|
DÉMONSTRATION 1 : LA MAUVAISE MÉTHODE (MD5)
|
|
==================================================================
|
|
*/
|
|
|
|
/**
|
|
* @route POST /users/register-bad
|
|
* @desc Enregistre un utilisateur avec MD5 (DANGEREUX !)
|
|
*/
|
|
router.post('/register-bad', (req, res) => {
|
|
try {
|
|
const { username, password } = req.body;
|
|
|
|
if (!username || !password) {
|
|
return res.status(400).json({ msg: 'Veuillez fournir un username et un password' });
|
|
}
|
|
|
|
// Hachage MD5 : rapide, synchrone, non salé.
|
|
// Une simple recherche Google ou Crackstation inverse ce hash.
|
|
const hash = crypto.createHash('md5').update(password).digest('hex');
|
|
|
|
// Stockage du hash "cassable"
|
|
fakeDatabase[username] = { hash, algorithm: 'md5' };
|
|
|
|
console.log('Utilisateur (MD5) créé :', fakeDatabase[username]);
|
|
|
|
res.status(201).json({
|
|
msg: 'Utilisateur créé avec MD5 (Non sécurisé !)',
|
|
username: username,
|
|
hash: hash,
|
|
// On montre que le mot de passe "123456" donne bien le hash connu
|
|
note: (password === '123456' ? 'Hash pour 123456: e10adc3949ba59abbe56e057f20f883e' : '')
|
|
});
|
|
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @route POST /users/login-bad
|
|
* @desc Connecte un utilisateur avec MD5
|
|
*/
|
|
router.post('/login-bad', (req, res) => {
|
|
const { username, password } = req.body;
|
|
const user = fakeDatabase[username];
|
|
|
|
if (!user || user.algorithm !== 'md5') {
|
|
return res.status(404).json({ msg: 'Utilisateur non trouvé ou mauvais algo' });
|
|
}
|
|
|
|
// On re-hache la tentative de mdp
|
|
const attemptHash = crypto.createHash('md5').update(password).digest('hex');
|
|
|
|
// Simple comparaison de chaînes.
|
|
if (user.hash === attemptHash) {
|
|
res.json({ msg: 'Connexion MD5 réussie ! (Mais vous n\'êtes pas en sécurité)' });
|
|
} else {
|
|
res.status(401).json({ msg: 'Mot de passe incorrect' });
|
|
}
|
|
});
|
|
|
|
|
|
/*
|
|
==================================================================
|
|
DÉMONSTRATION 2 : LA BONNE MÉTHODE (Argon2id)
|
|
==================================================================
|
|
*/
|
|
|
|
/**
|
|
* @route POST /users/register-good
|
|
* @desc Enregistre un utilisateur avec Argon2id (SÉCURISÉ)
|
|
*/
|
|
router.post('/register-good', async (req, res) => {
|
|
// La route est déclarée "async"
|
|
const { username, password } = req.body;
|
|
|
|
if (!username || !password) {
|
|
return res.status(400).json({ msg: 'Veuillez fournir un username et un password' });
|
|
}
|
|
|
|
try {
|
|
// 1. Le 'await' est crucial.
|
|
// Pendant que le CPU calcule le hash (ce qui est LENT),
|
|
// le thread principal de Node.js est libéré et peut traiter
|
|
// d'autres requêtes.
|
|
|
|
const hash = await argon2.hash(password, {
|
|
type: argon2.argon2id, // La variante la plus robuste
|
|
memoryCost: 2 ** 16, // 64Mo de RAM (65536 KiB)
|
|
timeCost: 3, // 3 itérations
|
|
parallelism: 1 // Utilise 1 cœur
|
|
});
|
|
|
|
// 2. Le hash contient le sel (salt) et les paramètres de coût.
|
|
// Il est auto-suffisant.
|
|
// ex: $argon2id$v=19$m=65536,t=3,p=1$Gb...
|
|
fakeDatabase[username] = { hash, algorithm: 'argon2id' };
|
|
|
|
console.log('Utilisateur (Argon2id) créé :', fakeDatabase[username]);
|
|
|
|
res.status(201).json({
|
|
msg: 'Utilisateur créé avec Argon2id (Sécurisé !)',
|
|
username: username,
|
|
hash: hash
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ msg: 'Erreur lors du hachage du mot de passe' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @route POST /users/login-good
|
|
* @desc Connecte un utilisateur avec Argon2id
|
|
*/
|
|
router.post('/login-good', async (req, res) => {
|
|
const { username, password } = req.body;
|
|
const user = fakeDatabase[username];
|
|
|
|
if (!user || user.algorithm !== 'argon2id') {
|
|
return res.status(404).json({ msg: 'Utilisateur non trouvé ou mauvais algo' });
|
|
}
|
|
|
|
try {
|
|
// 3. On utilise 'argon2.verify'
|
|
// Cette fonction lit le hash, extrait le sel et les paramètres,
|
|
// re-hache la tentative (password) et compare en temps constant.
|
|
const isMatch = await argon2.verify(user.hash, password);
|
|
|
|
if (isMatch) {
|
|
res.json({ msg: 'Connexion Argon2id réussie ! (Vous êtes en sécurité)' });
|
|
} else {
|
|
res.status(401).json({ msg: 'Mot de passe incorrect' });
|
|
}
|
|
|
|
} catch (err) {
|
|
// Si le format du hash est mauvais, ou autre erreur
|
|
console.error(err);
|
|
res.status(500).json({ msg: 'Erreur lors de la vérification' });
|
|
}
|
|
});
|
|
|
|
|
|
module.exports = router; |