La réalité du stockage des tokens dans le navigateur
Un regard pratique sur JWT dans le navigateur: XSS, CSRF, cookies, localStorage, service workers et compromis.
Les débats sur le stockage des tokens dans le navigateur finissent souvent en slogans: localStorage est mauvais, les cookies sont bons, ou l’inverse. Les applications réelles ont besoin d’un modèle de menace. Un JWT dans localStorage est facile à lire pour du JavaScript injecté. Un JWT dans un cookie HttpOnly n’est pas directement lisible par le script, mais il est envoyé automatiquement avec les requêtes et demande des contrôles CSRF. Aucune option ne sauve une application avec XSS large et APIs privilégiées sans contrôle supplémentaire.
Ce que veut l’attaquant
Avec XSS, l’attaquant cherche d’abord s’il peut voler le token ou simplement utiliser le navigateur de la victime comme mandataire confus. Si le token est dans localStorage, localStorage.getItem("access_token") est évident. S’il est dans un cookie HttpOnly, le vol direct est plus difficile, mais l’attaquant peut encore appeler des APIs same-origin depuis la page, sauf si CSP, validation des requêtes et confirmations d’actions sensibles réduisent l’impact.
La durée de vie du token change le calcul. Un access token de cinq minutes en mémoire avec un cookie de refresh n’a rien à voir avec un JWT de trente jours dans localStorage. Extensions de navigateur, machines partagées, dumps de crash, journaux et captures envoyées au support comptent aussi. Le choix de stockage n’est pas séparé des opérations.
Motifs courants et coûts
Garder les access tokens seulement en mémoire réduit le vol persistant, mais complique les rechargements, les onglets multiples et les flux hors ligne. Les cookies HttpOnly Secure SameSite conviennent à beaucoup d’applications web, mais les domaines API croisés et les contextes embarqués rendent parfois SameSite délicat. localStorage est simple et prévisible, mais chaque XSS devient extraction de token si le jeton n’est pas court et limité.
Détails défensifs importants
Configure Secure, HttpOnly et une valeur SameSite choisie volontairement sur les cookies. Utilise CSP avec nonces ou hashes, pas une politique qui autorise chaque domaine analytics à exécuter du script. Évite les tokens dans les URLs, car ils fuient via historique, referrers, journaux proxy et captures. N’envoie pas de bearer tokens dans la télémétrie frontend. Nettoie les en-têtes Authorization avant les outils de session replay.
Tester le stockage
Pendant une revue, simule l’attaquant plutôt que le diagramme. Un script injecté peut-il lire le token? Peut-il appeler /api/export ou /api/billing avec des cookies ambiants? Le logout révoque-t-il le chemin de refresh ou supprime-t-il seulement l’état client? Ouvre DevTools, inspecte le stockage, déclenche des erreurs et vérifie les payloads de télémétrie. Le meilleur design est celui dont le mode de panne a déjà été exercé.