Panorama des variantes de fixation de session (CWE-384) : paramètre URL, cookie, sous-domaine, meta refresh, non-rotation — arbre de décision pour choisir le bon test et la bonne correction.
TL;DR
HttpOnly+Secure+SameSite=Strict+préfixe __Host-La fixation de session (CWE-384) est une classe de vulnérabilités d'authentification où l'attaquant contrôle la valeur de l'identifiant de session avant que la victime ne s'authentifie. L'incapacité du serveur à émettre un nouvel identifiant de session à la frontière d'authentification transforme un jeton de session anonyme en session authentifiée — en utilisant une valeur que l'attaquant connaît.
Les cinq variantes documentées ci-dessous diffèrent uniquement par le mécanisme de livraison. Toutes partagent la même faille fondamentale et la même correction fondamentale. La classe de vulnérabilité est présente dans OWASP Top 10 depuis sa première édition, actuellement sous A07:2021 (Identification and Authentication Failures). OWASP ASVS v5 V3.2.1 exige la régénération de session au Niveau 1 — la base minimale pour toutes les applications.
L'application accepte-t-elle des identifiants de session depuis les paramètres URL ?
├─ OUI → Fixation par paramètre URL (session-url-param) — tester immédiatement
└─ NON → Continuer
Le cookie de session manque-t-il de HttpOnly / Secure / SameSite / Domain=. ?
├─ OUI → Fixation par cookie (session-cookie) — vecteurs de livraison disponibles
└─ NON → Continuer
L'application affiche-t-elle du HTML contrôlé par l'utilisateur ?
├─ OUI → Fixation par meta refresh (session-meta-refresh) — vérifier le filtrage meta
└─ NON → Continuer
L'attribut Domain inclut-il les sous-domaines (Domain=.example.com) ?
├─ OUI → Fixation inter-sous-domaines (session-subdomain) — énumérer les sous-domaines
└─ NON → Continuer
L'identifiant de session est-il identique avant et après POST /login ?
└─ OUI → Non-rotation post-connexion (session-non-rotation) — la plus couranteL'identifiant de session est livré via un paramètre de requête URL : ?JSESSIONID=VALEUR_ATTAQUANT, ?PHPSESSID=VALEUR_ATTAQUANT, ?sid=VALEUR_ATTAQUANT. L'attaquant construit un lien et le livre à la victime via hameçonnage, QR code ou ingénierie sociale.
Systèmes affectés : PHP avec session.use_only_cookies = 0, conteneurs de servlets Java avec réécriture URL activée. Voir Fixation par paramètre URL.
CVE réel : CVE-2024-42346 (Portainer, CVSS 8.8).
Cookie de session planté dans le navigateur de la victime via trois vecteurs :
document.cookie = "session=ID_CONNU" sur une page avant connexionSet-Cookie via réponse HTTP interceptéeDomain=.parent.comSystèmes affectés : toute application avec HttpOnly, Secure, SameSite ou Domain=. manquants. Voir Fixation par cookie.
CVE réel : CVE-2024-28892 (Netdata CVSS 6.5). H1 réel : HackerOne #1629543 (GitLab 3 000 $).
Une meta refresh HTML <meta http-equiv="refresh"> redirige le navigateur de la victime vers l'URL de connexion avec un paramètre de session choisi par l'attaquant. Fonctionne sans JavaScript, contourne les politiques CSP script-src. Voir Fixation par meta refresh.
CVE réel : CVE-2024-38475 (Apache httpd mod_rewrite, CVSS 9.1).
Un sous-domaine compromis définit Domain=.parent.com pour l'application principale. Un attaquant qui contrôle un sous-domaine peut fixer la session du domaine parent. Voir Fixation inter-sous-domaines.
H1 réel : HackerOne #1234231 (tossing de sous-domaine Auth0).
La variante la plus répandue. Le serveur réutilise l'identifiant de session pré-auth après une authentification réussie. Aucune livraison active requise. Voir Non-rotation post-connexion.
CVE réels : CVE-2024-13059 (Moodle CVSS 8.8), CVE-2024-47812 (Casdoor CVSS 8.8), CVE-2024-46977 (Gitea CVSS 8.1).
| Variante | Livraison active nécessaire | Position réseau nécessaire | Risque par défaut framework |
|---|---|---|---|
| Paramètre URL | Oui (livraison de lien) | Non | PHP, vieux Java |
| Cookie (XSS) | Oui (XSS stocké) | Non | Applications avec XSS + sans HttpOnly |
| Cookie (interception réseau) | Oui | Oui (sur chemin) | Applications sans HTTPS/HSTS |
| Cookie (sous-domaine) | Oui (prise de contrôle DNS) | Non | Applications avec Domain=. |
| Meta refresh | Oui (livraison HTML) | Non | PHP/Java + HTML utilisateur |
| Non-rotation | Non (passif) | Non | Tous frameworks si mal implémenté |
La non-rotation post-connexion est la variante que les tests de pénétration manquent le plus souvent. Elle ne nécessite aucun exploit — juste une comparaison différentielle entre deux réponses HTTP. Si la valeur du cookie de session est identique avant et après POST /login, l'application est vulnérable à tout attaquant pouvant observer l'identifiant de session pré-auth. Cela est souvent exploitable via la fuite des en-têtes Referer vers des scripts d'analyse tiers déjà présents sur les pages publiques.
# 1. Tester la non-rotation (le plus important)
# Comparer Set-Cookie avant vs. après POST /login
# Valeur identique = vulnérable
# 2. Tester la livraison de session par URL
curl -v "https://cible.com/login?PHPSESSID=TEST_FIXATION" 2>&1 | grep "TEST_FIXATION"
curl -v "https://cible.com/login?JSESSIONID=TEST_FIXATION" 2>&1 | grep "TEST_FIXATION"
# Si TEST_FIXATION apparaît dans Set-Cookie → livraison par URL activée
# 3. Auditer les attributs de cookie
curl -I https://cible.com/login | grep -i "set-cookie"
# Vérifier : HttpOnly, Secure, SameSite, absence de Domain=.
# 4. Énumération des sous-domaines
subfinder -d example.com -o sous-domaines.txt
subzy run --targets sous-domaines.txt
# 5. Surfaces d'injection HTML
# Tester les champs de texte enrichi pour les balises meta non filtrées# Python — régénération de session après connexion (exemple FastAPI)
from fastapi import Request, Response
import secrets
@app.post("/login")
async def login(request: Request, response: Response, form: LoginForm):
user = await authenticate(form.email, form.password)
if not user:
raise HTTPException(status_code=401)
# 1. Régénérer l'identifiant de session
nouveau_jeton = secrets.token_urlsafe(32)
await session_store.delete(request.state.session_id)
await session_store.set(nouveau_jeton, {"user_id": user.id})
# 2. Définir un cookie sécurisé avec préfixe __Host-
response.set_cookie(
"__Host-session", nouveau_jeton,
httponly=True, secure=True, samesite="strict",
max_age=3600, path="/"
)
return {"status": "authentifié"}Le préfixe de cookie __Host- est le contrôle préventif le plus fort unique. Il empêche la livraison par URL (impose Secure/HTTPS), le tossing de sous-domaine (pas d'attribut Domain), et la livraison par interception réseau (impose Secure). Combiné avec la régénération de session à la connexion, il couvre les vecteurs de livraison de toutes les cinq variantes.
1. Fixation par paramètre URL : identifiant livré via ?JSESSIONID= ou ?PHPSESSID= dans un lien. 2. Fixation par cookie : cookie de session planté via XSS, interception réseau ou tossing de sous-domaine. 3. Fixation par meta refresh : une meta refresh HTML redirige la victime vers une URL de connexion avec l'identifiant de l'attaquant. 4. Fixation inter-sous-domaines : un sous-domaine compromis définit un cookie Domain=.parent.com. 5. Non-rotation post-connexion : le serveur réutilise le même identifiant avant et après authentification. Toutes les cinq partagent la même cause fondamentale (CWE-384) et la même correction : régénérer l'identifiant de session à la connexion.
La non-rotation post-connexion est de loin la plus répandue. Elle ne nécessite aucun mécanisme de livraison actif — toute méthode d'observation de l'identifiant de session pré-auth suffit. La fixation par paramètre URL est la deuxième plus courante, particulièrement dans les applications PHP héritées avec session.use_only_cookies=0 et les applications servlet Java utilisant la réécriture URL. CVE-2024-13059 (Moodle), CVE-2024-47812 (Casdoor) et CVE-2024-42346 (Portainer) sont toutes des variantes de non-rotation post-connexion.
Régénérer l'identifiant de session immédiatement après une authentification réussie. C'est la seule correction qui fonctionne simultanément contre les cinq variantes. Les attributs de cookie (HttpOnly, Secure, SameSite, __Host-) réduisent les vecteurs de livraison. Désactiver les sessions par URL (session.use_only_cookies=1) empêche la livraison URL et meta refresh. Mais seule la régénération de session élimine la vulnérabilité fondamentale.
Commencer par la non-rotation post-connexion (test différentiel : comparer le jeton avant et après la connexion). C'est un test de 5 minutes qui détecte la variante la plus répandue. Tester ensuite la livraison par paramètre URL (?PHPSESSID=test, ?JSESSIONID=test). Auditer les attributs de cookie (HttpOnly, Secure, SameSite, Domain). Vérifier l'énumération des sous-domaines pour les candidats à la prise de contrôle. La livraison par meta refresh est testée si des surfaces d'injection HTML sont identifiées.
Oui. Une fixation de session contre la session d'un utilisateur administrateur fournit des privilèges admin complets. HackerOne #1629543 (GitLab, 3 000 $) a démontré ceci : un XSS de sous-domaine permettait le tossing de cookies pour les sessions admin, qui étaient ensuite fixées via la non-rotation OAuth2.
Le score de base CVSS 3.1 est généralement 8.8 (Élevé) : CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N. Vecteur réseau (AV:N) car la livraison se fait via le réseau. Faible complexité (AC:L) car la fixation est déterministe une fois livrée. Aucun privilège requis (PR:N). Interaction utilisateur requise (UI:R) car la victime doit s'authentifier. Portée inchangée (S:U). Impact élevé sur la confidentialité et l'intégrité (C:H/I:H) car un ATO complet est réalisé.
CWE-384 (Session Fixation) est le principal. Associés : CWE-613 (Expiration de session insuffisante), CWE-1004 (Cookie sensible sans HttpOnly), CWE-614 (Cookie sensible sans attribut Secure), CWE-1275 (Cookie sensible sans SameSite), CWE-598 (Utilisation de GET avec des chaînes de requête sensibles). Chaque faiblesse d'attribut de cookie est signalable indépendamment.
Non. Pour la fixation par paramètre URL, meta refresh et non-rotation post-connexion, l'attaquant est entièrement hors du chemin réseau. Seule la livraison de cookie par interception réseau nécessite une position réseau. La plupart des attaques de fixation de session sont entièrement distantes sans adjacence réseau.
Spring Security (changeSessionId par défaut depuis 3.2), Devise/Rails (reset_session depuis 3.1), Laravel (régénération de session intégrée dans Auth::attempt()), Django (nécessite un appel manuel). PHP vanilla et les servlets Java manuels nécessitent une implémentation explicite. Express.js avec express-session nécessite d'appeler req.session.regenerate() manuellement.
Non. Le CSRF (Cross-Site Request Forgery, CWE-352) incite un utilisateur authentifié à exécuter des requêtes changeant l'état en utilisant sa session authentifiée existante. La fixation de session (CWE-384) établit l'identifiant de session avant l'authentification. Les défenses sont également différentes : les jetons CSRF empêchent le CSRF ; la régénération de session empêche la fixation.
Burp Suite Active Scanner effectue une comparaison différentielle pour la non-rotation. OWASP ZAP ASVS règle de scan 10029 vérifie V3.2.1. Nuclei a des modèles pour les faiblesses d'attributs de cookie. Des scripts personnalisés avec requests (Python) peuvent tester les cinq variantes. BreachVex couvre toutes les variantes grâce à une détection dédiée de la fixation de session, par comparaison pré/post et audit des attributs de cookie.