Glossaire · Sécurité
Cross-site scripting (XSS)
En anglais : Cross-site scripting
Également appelé : XSS, faille XSS, cross site scripting, XSS stocké
Définition
Le XSS est une faille où une saisie non fiable s’exécute comme script dans le navigateur d’un autre utilisateur, permettant à un attaquant d’agir à sa place.
Le cross-site scripting (XSS) se produit lorsqu’une application prend une saisie d’un utilisateur et l’insère dans une page sans encodage approprié, si bien que le navigateur la traite comme du HTML ou du JavaScript au lieu de texte. Le script s’exécute alors avec la session de la victime sur le site vulnérable : il peut lire les données de la page, envoyer des requêtes au nom de l’utilisateur ou modifier ce qu’il voit. Dans l’OWASP Top 10 2021, il est regroupé sous A03 Injection.
Les trois types
- Stocké. La charge utile (payload) est enregistrée (un commentaire, un nom de profil, un ticket de support) et servie à tous ceux qui la consultent. C’est généralement le plus grave.
- Réfléchi. La charge utile se trouve dans la requête, souvent un paramètre d’URL comme un terme de recherche, et est renvoyée telle quelle dans la réponse.
- Basé sur le DOM. Du JavaScript côté client lit des données contrôlées par l’attaquant (par exemple
location.hash) et les écrit dans la page via un sink dangereux commeinnerHTML.
Ce que vérifie un testeur
Placez un marqueur inoffensif dans chaque champ affiché ensuite (à vous, aux autres utilisateurs, aux administrateurs dans un back-office) et regardez s’il revient sous forme de texte ou de balisage actif. Une vérification automatisée avec Playwright, uniquement pour des tests autorisés :
import { test, expect } from '@playwright/test';
test('comment body is rendered as text, not HTML', async ({ page }) => {
const probe = '<img src=x onerror="window.__xssProbe=1">';
await page.goto('/posts/1');
await page.getByLabel('Comment').fill(probe);
await page.getByRole('button', { name: 'Post comment' }).click();
// Escaped output shows the literal characters on screen
await expect(page.getByText(probe)).toBeVisible();
// and the handler never ran
expect(await page.evaluate(() => (window as any).__xssProbe)).toBeUndefined();
});
Vérifiez aussi les contextes de sortie au-delà du HTML simple : valeurs dans des attributs, dans des scripts inline, dans des URL (liens javascript:) et dans les éditeurs de texte riche, car chacun nécessite un encodage différent.
Défenses à vérifier
- Un encodage de sortie par défaut. Les frameworks modernes (React, Angular, Vue) échappent le texte automatiquement ; cherchez les échappatoires comme
dangerouslySetInnerHTML,v-htmlouinnerHTML. - Une sanitisation du HTML pour les fonctionnalités qui acceptent réellement du balisage.
- Un en-tête Content Security Policy qui bloque les scripts inline, comme seconde ligne de défense.
- Des cookies de session
HttpOnly, pour qu’un XSS réussi ne puisse pas simplement lire le cookie de session.
Ne testez jamais sur des systèmes qui ne vous appartiennent pas ou pour lesquels vous n’avez pas d’autorisation écrite.