Prévention XSS en Angular : sanitization automatique, DomSanitizer, trusted HTML/URL, Content Security Policy et bonnes pratiques de sécurité.
Introduction
Les attaques XSS (Cross-Site Scripting) figurent au TOP 3 des vulnérabilités OWASP. Elles injectent du code malveillant dans votre application pour voler des données ou contrôler les sessions. Angular vous protège automatiquement grâce à un système de sanitization intégré, mais il faut comprendre comment ça marche.
Qu'est-ce que le XSS ?
XSS signifie "injecter du code malveillant (JavaScript) qui s'exécute dans le navigateur de vos utilisateurs". Exemple :
// Commentaire d'un utilisateur malveillant
const evilComment = `
<script>
fetch('/api/steal-session', {
method: 'POST',
body: JSON.stringify({ cookie: document.cookie })
});
</script>
`;
// Si vous l'affichez sans protection dans les commentaires :
// Le script s'exécute dans le navigateur de TOUS les visiteurs
// ➜ Les cookies de session de chacun sont envoyés au serveur attaquant
- Stored XSS : Le code malveillant est stocké en BD (commentaires, posts, profils). Le plus dangereux.
- Reflected XSS : Le code vient de l'URL (paramètres GET). Ex:
example.com/search?q=<script>alert('xss')</script> - DOM XSS : JavaScript côté client modifie le DOM de manière non sécurisée. Ex:
element.innerHTML = userInput
Protection automatique d'Angular
Par défaut, Angular échappe automatiquement tous les caractères dangereux quand vous utilisez l'interpolation {{}} :
// component.ts
export class CommentComponent {
userComment = '<script>alert("XSS")</script>';
otherComment = '<img src=x onerror="alert(\'XSS\')">';
}
// template.html — SÉCURISÉ ✅
<p>{{ userComment }}</p>
<p>{{ otherComment }}</p>
// Rendu HTML : Les balises sont écrites en texte, pas exécutées
// <p><script>alert("XSS")</script></p>
// <p><img src=x onerror="alert('XSS')"></p>
<→<>→>"→"'→'
DomSanitizer — Quand vous avez besoin de HTML
Parfois, vous DEVEZ afficher du HTML riche (contenu d'éditeur, markdown compilé, etc.). C'est là qu'intervient DomSanitizer :
// component.ts
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { SecurityContext } from '@angular/core';
@Component({
selector: 'app-rich-content',
template: '<div [innerHTML]="safeHtml"></div>'
})
export class RichContentComponent {
safeHtml: SafeHtml;
constructor(private sanitizer: DomSanitizer) {
// Contenu provenant d'un éditeur riche (WYSIWYG)
const htmlFromEditor = `
<h2>Mon article</h2>
<p>Texte en <strong>gras</strong></p>
<img src="image.jpg" alt="Mon image">
<script>alert('Hack!')</script> <!-- Sera supprimé -->
`;
// Option 1 : Nettoyer en supprimant les balises dangereuses
this.safeHtml = this.sanitizer.sanitize(
SecurityContext.HTML,
htmlFromEditor
);
// Option 2 : Trusted HTML (dangereux, utilisez avec prudence)
// this.safeHtml = this.sanitizer.bypassSecurityTrustHtml(htmlFromEditor);
}
}
sanitize()→ Nettoie en supprimant les balises XSS (recommandé)bypassSecurityTrustHtml()→ Fait confiance au HTML (dangereux, à éviter)
Checklist de sécurité XSS
- ✅ Utiliser {{}} — Angular échappe automatiquement. C'est votre arme principale.
- ✅ [property] → safe. Ex:
[title]="userInput" - ✅ [attr.href] → safe. Angular vérifie l'URL.
- ✅ DomSanitizer.sanitize() → Safe pour le HTML riche (supprime les scripts).
- ❌ [innerHTML] → Dangereux sans DomSanitizer. Chaque {{ }} est plus sûr.
- ❌ bypassSecurityTrustHtml() → Très dangereux. Utilisez seulement si vous contrôlez 100% le contenu.
- ❌ eval(userInput) → Crime de sécurité. Jamais.
- ❌ new Function(userInput) → Pareil. Jamais.
- Validez TOUJOURS les entrées utilisateur (côté serveur)
- Activez une Content Security Policy (CSP) header
- Scannez vos dépendances npm avec
npm audit - Utilisez
ng-csp-noncepour les CSP nonce-based
Conclusion
Angular vous protège par défaut. Mais vous devez comprendre les règles :
{{}}= Safe ✅ (le 99% de vos cas)[innerHTML]+ DomSanitizer.sanitize() = Safe ✅ (HTML riche)[innerHTML]+ bypassSecurityTrustHtml() = Dangereux ⚠️ (seulement si you control 100%)- eval(), new Function() = Crime 🔴 (jamais)
{{}} — c'est toujours safe.