4.2Authentification & sécurité (JWT, bcrypt, Passport, Helmet)
Dès qu'une application a des utilisateurs et des données à protéger, l'authentification (vérifier QUI est l'utilisateur) et la sécurité deviennent cruciales — et c'est un domaine où les erreurs ont des conséquences graves (fuites de données, comptes compromis). Commençons par le stockage des mots de passe, le point le plus critique. Règle absolue : on ne stocke JAMAIS un mot de passe en clair. On stocke son hachage — une transformation à sens unique. La bibliothèque standard est bcrypt : elle hache le mot de passe (avec un « sel » aléatoire pour empêcher les attaques par tables précalculées) de façon volontairement LENTE (pour résister aux attaques par force brute). À l'inscription, on hache le mot de passe et on stocke le hachage ; à la connexion, on compare le mot de passe fourni au hachage stocké (bcrypt le fait sans jamais « déchiffrer » — c'est à sens unique). Ainsi, même si votre base est volée, les mots de passe ne sont pas exposés en clair. Ne JAMAIS coder son propre hachage « maison » : utilisez bcrypt (ou équivalent éprouvé).
Une fois l'utilisateur authentifié (mot de passe vérifié), il faut maintenir sa session à travers les requêtes suivantes (HTTP étant sans état). Deux approches principales. Les sessions (côté serveur) : le serveur crée une session et envoie un cookie d'identifiant ; à chaque requête, il retrouve la session. Les JWT (JSON Web Tokens) : après connexion, le serveur émet un jeton signé (un token contenant des informations sur l'utilisateur, signé cryptographiquement pour garantir qu'il n'a pas été falsifié) ; le client le renvoie à chaque requête (généralement dans l'en-tête Authorization), et le serveur le VÉRIFIE (sans avoir à stocker de session — le JWT est « auto-porteur »). Les JWT sont très populaires pour les API (sans état, adaptés aux fronts séparés et au mobile). Passport est une bibliothèque qui simplifie l'authentification (stratégies locales, OAuth avec Google/GitHub…). Au-delà de l'authentification, la sécurité englobe bien plus : l'autorisation (une fois authentifié, l'utilisateur a-t-il le DROIT de faire cette action ? — 401 non authentifié vs 403 non autorisé), la protection contre les failles web classiques (injection — vue en 3-4 —, XSS, CSRF), l'usage de HTTPS (chiffrer les communications), la gestion sûre des secrets (clés, mots de passe de base — dans des variables d'environnement, JAMAIS dans le code), Helmet (un middleware Express qui définit des en-têtes HTTP de sécurité), la limitation de débit (rate limiting, contre les abus/force brute), et la validation des entrées (section 4-4). Un principe fondamental et transversal : ne jamais faire confiance aux entrées ni au client — tout ce qui vient de l'extérieur est potentiellement malveillant, à valider et traiter avec prudence. La sécurité n'est pas une « fonctionnalité en plus » à ajouter à la fin : c'est une préoccupation permanente, intégrée dès la conception. Les enjeux sont réels (les fuites de données et compromissions font régulièrement l'actualité, avec des conséquences lourdes). Un développeur back-end DOIT connaître ces bases de sécurité — hachage des mots de passe (bcrypt), authentification (JWT/sessions), autorisation, protection des secrets, failles courantes. Ce n'est pas optionnel : c'est une responsabilité professionnelle et éthique (vous manipulez les données et les comptes de vraies personnes).
Vocabulaire de la section
- Hachage des mots de passe (bcrypt)
- On ne stocke JAMAIS un mot de passe en clair, mais son hachage à sens unique (bcrypt, avec sel, volontairement lent). À la connexion, on compare sans déchiffrer.
- JWT (JSON Web Token)
- Jeton signé cryptographiquement émis après connexion, renvoyé par le client à chaque requête (en-tête Authorization) et vérifié par le serveur ; sans état, populaire pour les API.
- Session vs JWT
- Session : état côté serveur + cookie d'identifiant. JWT : jeton auto-porteur sans stockage serveur. Deux façons de maintenir l'authentification (HTTP étant sans état).
- Authentification vs autorisation
- Authentification : QUI est l'utilisateur (401 si non authentifié). Autorisation : a-t-il le DROIT de faire cette action (403 si non autorisé).
- Sécurité transversale
- Helmet (en-têtes de sécurité), HTTPS, secrets en variables d'environnement (jamais dans le code), rate limiting, validation — et « ne jamais faire confiance aux entrées ».
Pourquoi ne JAMAIS stocker les mots de passe en clair ?
En pratique — Sécuriser l'authentification
- Hachez les mots de passe avec bcrypt à l'inscription (jamais en clair !) et comparez à la connexion (bcrypt.compare, sans déchiffrer).
- Émettez un JWT signé après connexion réussie ; le client le renvoie dans l'en-tête Authorization à chaque requête.
- Écrivez un middleware qui VÉRIFIE le JWT sur les routes protégées (401 si absent/invalide) et attache l'utilisateur à req.user.
- Ajoutez la sécurité transversale : Helmet (en-têtes), secrets dans des variables d'environnement (.env, jamais dans le code ni Git), et distinguez 401 (non authentifié) / 403 (non autorisé).
Points clés à retenir
- JAMAIS de mot de passe en clair : stocker le HACHAGE avec BCRYPT (à sens unique, avec sel, lent). À la connexion, comparer sans déchiffrer. Ne jamais coder son hachage « maison ».
- Maintenir l'authentification (HTTP sans état) : SESSIONS (état serveur + cookie) ou JWT (jeton signé auto-porteur renvoyé à chaque requête, populaire pour les API). Passport simplifie.
- AUTHENTIFICATION (qui es-tu ? 401) vs AUTORISATION (as-tu le droit ? 403) — deux choses distinctes à gérer.
- Sécurité transversale : Helmet (en-têtes), HTTPS, SECRETS en variables d'environnement (jamais dans le code/Git), rate limiting, validation. Principe : NE JAMAIS FAIRE CONFIANCE aux entrées. La sécurité est une responsabilité permanente.
Questions fréquentes
Pourquoi ne jamais stocker les mots de passe en clair, et comment bcrypt protège-t-il vraiment ?
C'est LA règle de sécurité la plus fondamentale concernant les mots de passe, et la comprendre (avec le fonctionnement de bcrypt) est essentiel — car une erreur ici expose les mots de passe de TOUS vos utilisateurs, avec des conséquences graves. Pourquoi ne JAMAIS stocker en clair : imaginez que vous stockez les mots de passe tels quels dans votre base (password: "monMotDePasse123"). Si votre base est un jour COMPROMISE (piratage, fuite, employé malveillant, sauvegarde volée — cela arrive RÉGULIÈREMENT, l'actualité en témoigne), TOUS les mots de passe sont immédiatement exposés en clair. Conséquences dramatiques : (1) l'attaquant peut se connecter à tous les comptes de votre application ; (2) PIRE — beaucoup d'utilisateurs RÉUTILISENT le même mot de passe ailleurs (email, banque, autres services), donc l'attaquant peut compromettre leurs autres comptes (« credential stuffing »). Votre fuite met en danger les utilisateurs bien au-delà de votre application. C'est une catastrophe éthique et légale (responsabilité, sanctions RGPD…). Stocker en clair est une faute grave et inexcusable. La solution : le HACHAGE. Au lieu du mot de passe, on stocke son HACHAGE — le résultat d'une fonction à SENS UNIQUE : facile à calculer dans un sens (mot de passe → hachage), impossible à inverser (hachage → mot de passe). On ne peut pas « retrouver » le mot de passe depuis le hachage. Comment ça marche en pratique : (1) À l'INSCRIPTION : on hache le mot de passe fourni et on stocke LE HACHAGE (jamais le mot de passe). (2) À la CONNEXION : on hache le mot de passe fourni et on COMPARE au hachage stocké — s'ils correspondent, le mot de passe est bon (on n'a jamais eu besoin de « déchiffrer » quoi que ce soit). Résultat : si la base est volée, l'attaquant n'a que des HACHAGES, pas les mots de passe — il ne peut pas se connecter directement. Pourquoi BCRYPT spécifiquement (et pas un simple hachage) : un hachage naïf (comme MD5 ou SHA rapide) ne suffit PAS, pour deux raisons que bcrypt résout : (1) Le SEL (salt). Sans sel, deux utilisateurs avec le même mot de passe auraient le même hachage, et des attaquants utilisent des « tables arc-en-ciel » (tables précalculées de hachages de mots de passe courants) pour retrouver les mots de passe. bcrypt ajoute un SEL aléatoire UNIQUE à chaque mot de passe avant de le hacher — ainsi, même deux mots de passe identiques ont des hachages différents, et les tables précalculées deviennent inutiles (il faudrait une table par sel). Le sel est stocké avec le hachage (c'est prévu, il n'a pas à être secret). (2) La LENTEUR VOLONTAIRE (facteur de coût). Un hachage rapide (MD5, SHA) permet à un attaquant de tester des MILLIARDS de mots de passe par seconde (force brute) si votre base fuite. bcrypt est VOLONTAIREMENT LENT (et son coût est réglable) — hacher prend un temps notable (des dizaines/centaines de millisecondes). Pour votre application, c'est négligeable (on ne hache qu'à l'inscription/connexion). Mais pour un attaquant qui veut tester des milliards de possibilités, cette lenteur rend la force brute BEAUCOUP plus coûteuse et lente — une protection majeure. De plus, le facteur de coût est AJUSTABLE : on peut l'augmenter à mesure que les ordinateurs deviennent plus rapides, gardant bcrypt résistant dans le temps. Les règles à retenir : (1) JAMAIS de mot de passe en clair — toujours haché. (2) Utilisez bcrypt (ou un équivalent moderne éprouvé comme Argon2, scrypt) — PAS un simple MD5/SHA (trop rapides, cassables), PAS un hachage « maison » (vous feriez des erreurs). Les bibliothèques éprouvées gèrent le sel et la lenteur correctement. (3) Ne « déchiffrez » jamais un mot de passe (c'est à sens unique — d'où le fait qu'une application sérieuse ne peut pas vous RENVOYER votre mot de passe oublié, seulement vous permettre de le RÉINITIALISER — un signe de bonne sécurité). Points liés : (1) encouragez des mots de passe FORTS (longueur, complexité) et envisagez l'authentification à deux facteurs (2FA) pour plus de sécurité. (2) La sécurité des mots de passe n'est qu'un aspect (l'authentification, l'autorisation, les failles web, HTTPS, les secrets… comptent aussi). Mais le hachage des mots de passe est un fondamental ABSOLU. En résumé : ne jamais stocker en clair (une fuite exposerait tous les mots de passe, mettant en danger vos utilisateurs partout) ; stocker le HACHAGE via bcrypt, qui protège par le SEL (contre les tables précalculées) et la LENTEUR volontaire ajustable (contre la force brute). C'est un savoir de sécurité non négociable pour tout développeur qui gère des comptes — une responsabilité envers de vraies personnes dont vous protégez les données. Une application qui stocke les mots de passe en clair est une faute professionnelle grave ; utiliser bcrypt correctement est le minimum vital.
La sécurité semble vaste et intimidante : par où commencer et quel état d'esprit adopter ?
La sécurité EST vaste, et c'est normal de se sentir dépassé — mais on peut l'aborder progressivement en commençant par les fondamentaux à fort impact, et surtout en adoptant le bon ÉTAT D'ESPRIT, qui est plus important que de connaître toutes les failles. L'état d'esprit fondamental : « ne jamais faire confiance aux entrées ni au client ». C'est LE principe qui sous-tend la sécurité web. Tout ce qui vient de l'EXTÉRIEUR (données de formulaires, paramètres d'URL, en-têtes, corps de requêtes, fichiers uploadés, et même les requêtes venant de « votre » front — car un attaquant peut envoyer des requêtes directement, sans passer par votre interface) est POTENTIELLEMENT MALVEILLANT. Vous devez traiter toute entrée comme suspecte : la valider, l'assainir, la manipuler avec prudence (requêtes paramétrées, échappement, contrôles). Cet état d'esprit défensif — supposer le pire des entrées — vous fait éviter une grande partie des failles, même celles que vous ne connaissez pas nommément. Par où COMMENCER (les fondamentaux à fort impact) : (1) Mots de passe : bcrypt. Ne jamais stocker en clair, toujours hacher avec bcrypt. Fondamental et à fort impact (une fuite exposerait tout). (2) Ne jamais faire confiance aux entrées : validez les données (section 4-4), utilisez des requêtes paramétrées/ORM (contre l'injection SQL, section 3-4), assainissez ce qui sera affiché (contre le XSS). (3) Protéger les SECRETS : les clés, mots de passe de base, secrets JWT ne doivent JAMAIS être dans le code ni dans Git — utilisez des variables d'environnement (.env, ignoré par Git). Une fuite de secret (une clé dans un dépôt public) est une faille classique et grave. (4) HTTPS : chiffrer les communications (indispensable en production — sinon mots de passe et données circulent en clair). (5) Authentification et autorisation correctes : vérifier QUI (authentification) ET vérifier le DROIT (autorisation) — ne pas confondre, ne pas oublier l'autorisation (un utilisateur authentifié ne doit pas pouvoir accéder aux données d'un AUTRE utilisateur — une faille fréquente et grave). (6) Helmet : un middleware qui définit des en-têtes HTTP de sécurité (facile à ajouter, gain immédiat). (7) Garder les dépendances à jour (npm audit, section 1-4) : les failles de dépendances sont un vecteur réel. (8) Rate limiting : limiter les requêtes (contre la force brute, les abus). Avec ces fondamentaux, vous couvrez déjà une grande partie des risques courants. Comment PROGRESSER (sans se noyer) : (1) Commencez par les fondamentaux ci-dessus — ils ont le meilleur rapport impact/effort. Ne cherchez pas à tout maîtriser d'un coup. (2) Apprenez les failles COURANTES progressivement : l'injection (SQL/NoSQL), le XSS (cross-site scripting — injection de scripts), le CSRF (cross-site request forgery), les problèmes d'authentification/autorisation, l'exposition de données sensibles. Des ressources comme l'« OWASP Top 10 » (la liste des principales failles web) sont d'excellents guides d'apprentissage structurés. (3) Utilisez des outils et bibliothèques éprouvés : bcrypt pour les mots de passe, des bibliothèques d'auth (Passport), de validation (Zod/Joi), Helmet — ne réinventez pas la sécurité, appuyez-vous sur ce qui est testé par la communauté. (4) Restez informé : la sécurité évolue (nouvelles failles, nouvelles pratiques). (5) Testez et faites relire : les revues de code et, sur les projets sérieux, les audits de sécurité aident. L'état d'esprit global : (1) la sécurité est une PRÉOCCUPATION PERMANENTE, pas une fonctionnalité à ajouter à la fin. Pensez sécurité DÈS la conception (« comment cette entrée pourrait-elle être abusée ? », « qui a le droit d'accéder à ça ? »). (2) Adoptez la posture DÉFENSIVE (ne pas faire confiance aux entrées, supposer le pire). (3) Acceptez de ne pas tout savoir — commencez par les fondamentaux, apprenez progressivement, utilisez des outils éprouvés. (4) Prenez la RESPONSABILITÉ au sérieux : vous manipulez les données et comptes de vraies personnes ; une faille peut leur nuire réellement. La sécurité est une obligation éthique et professionnelle. En résumé : ne soyez pas paralysé par l'ampleur de la sécurité — commencez par les fondamentaux à fort impact (bcrypt, ne pas faire confiance aux entrées, protéger les secrets, HTTPS, auth/autorisation correctes, Helmet, dépendances à jour), adoptez l'état d'esprit défensif (« ne jamais faire confiance aux entrées »), appuyez-vous sur des outils éprouvés, et apprenez progressivement les failles courantes (OWASP Top 10). L'état d'esprit (méfiance envers les entrées, sécurité dès la conception, responsabilité) compte plus que de connaître toutes les failles par cœur. Un développeur qui INTÈGRE ces réflexes de base et cette posture défensive évite déjà l'immense majorité des problèmes — bien plus qu'un développeur qui connaît des failles obscures mais néglige les fondamentaux. La sécurité est un pilier du métier de développeur back-end : prenez-la au sérieux dès le début, progressivement mais résolument.
Autres ressources
.env).