Dónde guardar el token de autenticación para sobrevivir a un XSS

Fuentes: Where should your auth token live so an XSS bug can't steal it?

Almacenar el token JWT en localStorage es la opción más extendida en los tutoriales, pero también la más expuesta: cualquier JavaScript que se ejecute en la página (una dependencia comprometida, un widget de terceros, una extensión del navegador o el propio código del atacante tras un XSS) puede leerlo con una sola línea y llevárselo a su infraestructura. A partir de ahí, "el que lleva el token es el usuario": el servidor valida la firma y concede acceso desde cualquier lugar del mundo hasta que expire, sin que el legítimo dueño pueda revocarlo.

El artículo examina por qué la frase "si pueden ejecutar JS ya estás muerto" solo es verdad a medias. Si el atacante lee el token, se lleva una llave maestra que sigue funcionando con la pestaña cerrada; si solo puede montar la sesión activa, queda confinado a las peticiones que se ejecutan en el navegador de la víctima, a la vista de los registros, los rate limits y los controles antifraude del servidor. La diferencia es la que existe entre una llave robada y un ladrón que solo puede actuar mientras está dentro de la casa.

La siguiente opción analizada es mantener el token solo en memoria (una variable del módulo). Es más difícil de localizar que localStorage, pero no es segura: un script malicioso puede parchear window.fetch y capturar el token cuando la app lo adjunta. Además, al refrescar la página o abrir otra pestaña la sesión se pierde, por lo que se introduce un refresh token de larga duración, que a su vez vuelve al problema de dónde guardarlo. Si termina en localStorage, el atacante lo roba y fabrica access tokens para siempre. Cualquier almacenamiento al que JavaScript pueda acceder acaba siendo inseguro.