# Démonstration A07:2025 - Authentication Failures ## Objectif de la démonstration Cet atelier illustre concrètement plusieurs vulnérabilités de la catégorie **A07:2025 - Authentication Failures** (échecs d'authentification) de l'owasp. Vous n'avez **aucun code à écrire**. Votre rôle est d'analyser le comportement de deux points de terminaison (endpoints) à l'aide de postman et d'observer les journaux (logs) du serveur. ## Contexte du projet Le code `routes/index.js` contient deux routes d'authentification: 1. `POST /login-vulnerable`: une implémentation intentionnellement faible. 2. `POST /login-securise`: une implémentation corrigée et sécurisée. ## Prérequis * Node.js et npm installés. * Le logiciel postman (ou un équivalent pour tester les api). * Ce projet (avec les `node_modules` installés via `npm install`). ## Instructions de lancement 1. Ouvrez un terminal (par exemple, le terminal intégré de webstorm). 2. Lancez le serveur en mode "watch" avec la commande: ```bash nodemon ./bin/www ``` 3. Gardez cette console visible. C'est ici que vous lirez les journaux (logs) du serveur. 4. Ouvrez postman pour effectuer les tests décrits ci-dessous. --- ## Partie 1: Analyse du point de terminaison vulnérable Testez l'endpoint `POST http://localhost:3000/login-vulnerable` avec postman. Assurez-vous d'envoyer vos données en `raw` -> `json` dans l'onglet `Body`. ```mermaid flowchart TD a["client envoie requête vers /login-vulnerable"] --> b["serveur recherche l'utilisateur"] b --> c{"utilisateur trouvé ?"} c -- "non" --> d["retour 404 avec message 'utilisateur non trouvé'"] c -- "oui" --> e{"mot de passe valable ?"} e -- "non" --> f["retour 400 avec message 'mot de passe incorrect'"] e -- "oui" --> g["session non régénérée"] g --> h["retour 200 'connexion vulnérable réussie'"] ``` ### Faille 1: énumération de comptes L'énumération de comptes permet à un attaquant de deviner quels utilisateurs existent dans la base de données en analysant les différentes réponses du serveur. **Test A: utilisateur inexistant** * Requête (body): ```json { "username": "un_utilisateur_inconnu", "password": "123" } ``` * Réponse (status 404): `Erreur : Utilisateur non trouvé.` **Test B: utilisateur existant, mauvais mot de passe** * Requête (body): ```json { "username": "admin", "password": "mauvais_mot_de_passe" } ``` * Réponse (status 400): `Erreur : Mot de passe incorrect.` **Conclusion de la faille 1:** Les messages d'erreur sont différents. Un attaquant peut créer un script pour tester des milliers de noms d'utilisateurs et savoir lesquels sont valides (ceux qui retournent "mot de passe incorrect"). ### Faille 2: mots de passe en clair et absence de limitation Cette route compare directement le mot de passe reçu avec un mot de passe stocké en clair (`password_vulnerable`). ```mermaid flowchart TD a["client envoie requête vers /login-securise"] --> b["serveur recherche l'utilisateur (sans distinction dans la réponse)"] b --> c["vérification avec 'bcrypt.compare'"] c --> d{"identifiants valides ?"} d -- "non" --> e["retour 401 'identifiants invalides'"] d -- "oui" --> f["regeneration de la session"] f --> g["retour 200 'connexion sécurisée réussie'"] ``` **Test C: attaque par force brute** * Le serveur n'implémente aucune limitation de tentatives (rate limiting). * Un attaquant pourrait tester des millions de mots de passe pour l'utilisateur "admin" sans jamais être bloqué. ### Faille 3: fixation de session La fixation de session se produit lorsque l'identifiant de session d'un utilisateur n'est pas renouvelé après une authentification réussie. **Test D: connexion réussie** * Requête (body): ```json { "username": "admin", "password": "password123" } ``` * Réponse (status 200): `Connexion (vulnérable) réussie pour admin !` * **Action requise:** regardez maintenant la console de votre serveur (dans webstorm). * Vous devriez voir les logs suivants: ``` [VULNÉRABLE] Session AVANT login: [un long identifiant] [VULNÉRABLE] Session APRÈS login: [le même identifiant] (INCHANGÉE) ``` **Conclusion de la faille 3:** L'identifiant de session est le même avant et après le login. Si un attaquant parvenait à "fixer" (donner) un identifiant de session à un utilisateur avant sa connexion (par exemple, via un lien piégé), il pourrait usurper son identité une fois l'utilisateur connecté. --- ## Partie 2: Analyse du point de terminaison corrigé Testez maintenant l'endpoint `POST http://localhost:3000/login-securise`. ### Correction 1: prévention de l'énumération de comptes **Test A (corrigé): utilisateur inexistant** * Requête (body): ```json { "username": "un_utilisateur_inconnu", "password": "123" } ``` * Réponse (status 401): `Identifiants invalides.` **Test B (corrigé): utilisateur existant, mauvais mot de passe** * Requête (body): ```json { "username": "admin", "password": "mauvais_mot_de_passe" } ``` * Réponse (status 401): `Identifiants invalides.` **Conclusion de la correction 1:** La réponse est identique dans les deux cas. Il est désormais impossible pour un attaquant de distinguer un nom d'utilisateur invalide d'un mot de passe invalide. ### Correction 2: hachage et régénération de session **Test D (corrigé): connexion réussie** * Le code utilise `bcrypt.compare` pour comparer de manière sécurisée le mot de passe fourni avec le hash stocké. * Requête (body): ```json { "username": "admin", "password": "password123" } ``` * Réponse (status 200): `Connexion (sécurisée) réussie pour admin !` * **Action requise:** regardez à nouveau la console du serveur. * Vous devriez voir ces logs: ``` [SÉCURISÉ] Session AVANT login: [un premier identifiant] [SÉCURISÉ] Session APRÈS login: [un nouvel identifiant] (CHANGÉE) ``` **Conclusion de la correction 2:** Le serveur a explicitement régénéré la session (`req.session.regenerate`). L'ancien identifiant est invalidé et un nouveau est créé, empêchant toute attaque de type "fixation de session". ### Correction 3: limitation des tentatives (rate limiting) **Test E (corrigé): attaque par force brute** * Envoyez la requête du "Test B (corrigé)" (avec un mauvais mot de passe) 11 fois de suite. * Les 10 premières tentatives renverront `Identifiants invalides.` * À la 11ème tentative (et pour les suivantes pendant 15 minutes), vous recevrez: * Réponse (status 429): `Trop de tentatives de connexion. Réessayez dans 15 minutes.` **Conclusion de la correction 3:** Le serveur empêche activement les attaques par force brute ou par "credential stuffing" en limitant le nombre d'échecs autorisés par adresse ip. ## Conclusion Cette démonstration a mis en évidence plusieurs vulnérabilités courantes liées à l'authentification, ainsi que les mesures correctives appropriées pour les atténuer. ```mermaid flowchart LR a["vulnérabilité : énumération de comptes"] --> b["risque : découverte des utilisateurs valides"] c["vulnérabilité : mots de passe en clair"] --> d["risque : compromission immédiate"] e["vulnérabilité : pas de rate limiting"] --> f["risque : force brute illimitée"] g["vulnérabilité : session non régénérée"] --> h["risque : fixation de session"] i["mesure : message d'erreur uniforme"] --> a j["mesure : mot de passe hashé"] --> c k["mesure : rate limiting"] --> e l["mesure : regeneration de session"] --> g ```