Cross-Site Scripting (XSS)
Cross-Site Scripting (XSS)
Description
Les vulnérabilités de type Cross-Site Scripting (XSS) surviennent lorsqu'une entrée contrôlée par l'utilisateur, non aseptisée, est renvoyée à l'utilisateur.
Les vulnérabilités XSS contournent la Same-Origin Policy (SOP), qui est un principe fondamental de la sécurité web. La SOP garantit qu'une page provenant de http://evil.com ne peut pas accéder au contenu d'une page provenant de http://bank.com.
Les attaques XSS sont généralement classées en trois familles :
- Reflected : l'entrée contrôlée par l'utilisateur est directement reflétée dans la réponse de la page.
- Stored : l'entrée contrôlée par l'utilisateur est stockée côté serveur (par exemple, dans une base de données) et est ultérieurement renvoyée à l'utilisateur.
- DOM-based : l'entrée contrôlée par l'utilisateur est injectée côté client dans le DOM, déclenchant l'exécution de code JavaScript malveillant.
Les vulnérabilités XSS permettent à un attaquant de réaliser diverses actions malveillantes, telles que l'exfiltration de données personnelles (y compris les sessions utilisateur ou les informations de compte) et d'exécuter des actions au nom de l'utilisateur.
Exemples
import javax.servlet.http.*;
import java.io.*;
public class VulnerableXSS extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String userInput = request.getParameter("input");
String page = "<html><body><h2>User Input: " + userInput + "</h2></body></html>";
PrintWriter out = response.getWriter();
out.println(page);
}
}
const express = require('express');
const app = express();
app.get('/vulnerable', (req, res) => {
const userInput = req.query.input;
res.send(`<html><body><h2>User Input: ${userInput}</h2></body></html>`);
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
<!DOCTYPE html>
<html>
<head>
<title>XSS Vulnerability</title>
</head>
<body>
<h1>Welcome to the Vulnerable Page</h1>
<p>Search for a product:</p>
<form action="/search">
<input type="text" name="query" placeholder="Enter product name">
<input type="submit" value="Search">
</form>
<p>Search results:</p>
<div id="results">
<!-- Display search results here -->
<?php
// Vulnerable code - directly echoing user input without sanitization
$query = $_GET['query'];
echo "<p>You searched for: " . $query . "</p>";
?>
</div>
</body>
</html>
Recommandation
Dans la majorité des cas, la prévention des vulnérabilités XSS nécessite une protection en deux étapes :
- Validation des entrées : les entrées contrôlées par l'utilisateur doivent être validées pour interdire tout caractère non autorisé. Par exemple, un numéro de téléphone ne doit contenir que des chiffres ; les noms ne doivent contenir que des caractères alphabétiques, etc.
- Encodage des sorties : toute entrée affichée à l'utilisateur doit être correctement encodée à l'aide d'une API standard éprouvée. L'utilisation de moteurs de templates sécurisés, prenant en charge nativement l'encodage des sorties et disposant de configurations par défaut sécurisées, est fortement recommandée.
Exemples
import org.apache.commons.text.StringEscapeUtils;
import javax.servlet.http.*;
import java.io.*;
public class SecureXSSWithLibrary extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String userInput = request.getParameter("input");
String sanitizedInput = StringEscapeUtils.escapeHtml4(userInput);
String page = "<html><body><h2>User Input: " + sanitizedInput + "</h2></body></html>";
PrintWriter out = response.getWriter();
out.println(page);
}
}
const express = require('express');
const app = express();
const { escape } = require('html-escaper'); // Using 'html-escaper' library
app.get('/secure', (req, res) => {
const userInput = req.query.input;
const sanitizedInput = escape(userInput);
res.send(`<html><body><h2>User Input: ${sanitizedInput}</h2></body></html>`);
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
<!DOCTYPE html>
<html>
<head>
<title>Secure Page</title>
</head>
<body>
<h1>Welcome to the Secure Page</h1>
<p>Search for a product:</p>
<form action="/search">
<input type="text" name="query" placeholder="Enter product name">
<input type="submit" value="Search">
</form>
<p>Search results:</p>
<div id="results">
<!-- Display sanitized search results here -->
<?php
// Sanitizing user input before displaying
$query = $_GET['query'];
echo "<p>You searched for: " . htmlspecialchars($query, ENT_QUOTES, 'UTF-8') . "</p>";
?>
</div>
</body>
</html>
Liens
- CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
- CWE-80: Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)
- CWE-116: Improper Encoding or Escaping of Output
- CWE-159: Failure to Sanitize Special Element
Normes
- OWASP_ASVS_L1:
- V5_2_1
- V5_3_1
- V13_1_1
- OWASP_ASVS_L2:
- V5_2_1
- V1_5_4
- V5_3_1
- V13_1_1
- OWASP_ASVS_L3:
- V5_2_1
- V1_5_4
- V5_3_1
- V13_1_1
- PCI_STANDARDS:
- REQ_2_2
- REQ_6_2
- REQ_6_3
- REQ_6_4
- REQ_11_3
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213
- SECURITY255