¿Dónde almacenar JWT en el navegador? ¿Cómo protegerse contra CSRF?
Conozco la autenticación basada en cookies. Se pueden aplicar indicadores SSL y HttpOnly para proteger la autenticación basada en cookies de MITM y XSS. Sin embargo, será necesario aplicar más medidas especiales para protegerlo del CSRF. Son un poco complicados. ( referencia )
Recientemente, descubrí que JSON Web Token (JWT) es una solución bastante interesante para la autenticación. Sé todo sobre codificar, decodificar y verificar JWT. Sin embargo, no entiendo por qué algunos sitios web/tutoriales dicen que no es necesaria la protección CSRF si se utiliza JWT. He leído bastante y he intentado resumir los problemas a continuación. Solo quiero que alguien me brinde una visión más amplia de JWT y aclare los conceptos que entendí mal sobre JWT.
Si el JWT se almacena en una cookie, creo que es lo mismo que la autenticación basada en cookies, excepto que el servidor no necesita tener sesiones para verificar la cookie/token. Todavía existe el riesgo de que se produzca un CSRF si no se implementan medidas especiales. ¿No se almacena JWT en una cookie?
Si el JWT se almacena en localStorage/sessionStorage, entonces no hay ninguna cookie involucrada, por lo que no es necesario protegerlo contra CSRF. La pregunta es cómo enviar el JWT al servidor. Aquí encontré que se sugiere usar jQuery para enviar el JWT mediante el encabezado HTTP de las solicitudes ajax. Entonces, ¿solo las solicitudes ajax pueden realizar la autenticación?
Además, encontré un blog más que apunta al uso de "Encabezado de autorización" y "Portador" para enviar el JWT. No entiendo el método del que habla el blog. ¿Alguien podría explicar más sobre el "encabezado de autorización" y el "portador"? ¿Esto hace que el JWT se transmita mediante el encabezado HTTP de TODAS las solicitudes? En caso afirmativo, ¿qué pasa con CSRF?
Necesitamos almacenar el JWT en la computadora cliente. Si lo almacenamos en un LocalStorage/SessionStorage, un ataque XSS puede capturarlo fácilmente. Si lo almacenamos en cookies, un pirata informático puede usarlo (sin leerlo) en un ataque CSRF y hacerse pasar por el usuario y contactar nuestra API y enviar solicitudes para realizar acciones u obtener información en nombre de un usuario.
Pero hay varias formas de proteger los JWT en las cookies para que no sean robados fácilmente (pero todavía existen algunas técnicas avanzadas para robarlos). Pero si desea confiar en LocalStorage/SessionStorage, puede acceder a él mediante un simple ataque XSS.
Entonces, para resolver el problema CSRF, utilizo cookies de envío doble en mi aplicación.
Método de envío doble de cookies
Almacene JWT en una cookie HttpOnly y utilícelo en modo seguro para transferir a través de HTTPS.
La mayoría de los ataques CSRF tienen un origen o encabezado de referencia diferente con su host original en sus solicitudes. Así que comprueba si tienes alguno de ellos en el encabezado, ¡provienen de tu dominio o no! Si no, rechacelos. Si tanto el origen como el referente no están disponibles en la solicitud, no se preocupe. Puede confiar en el resultado de la validación del encabezado X-XSRF-TOKEN que explico en el siguiente paso.
Si bien el navegador proporcionará automáticamente las cookies para el dominio de la solicitud, existe una limitación útil: el código JavaScript que se ejecuta en un sitio web no puede leer las cookies de otros sitios web. Podemos aprovechar esto para crear nuestra solución CSRF. Para evitar ataques CSRF, debemos crear una cookie adicional legible en Javascript que se llama: XSRF-TOKEN. Esta cookie debe crearse cuando el usuario inicia sesión y debe contener una cadena aleatoria e imposible de adivinar. También guardamos este número en el propio JWT como reclamo privado. Cada vez que la aplicación JavaScript quiera realizar una solicitud, deberá leer este token y enviarlo en un encabezado HTTP personalizado. Debido a que estas operaciones (leer la cookie, configurar el encabezado) solo se pueden realizar en el mismo dominio de la aplicación JavaScript, podemos saber que esto lo realiza un usuario real que está utilizando nuestra aplicación JavaScript.
Angular JS te hace la vida más fácil
Afortunadamente, estoy usando Angular JS en nuestra plataforma y Angular empaqueta el enfoque de token CSRF, lo que nos facilita la implementación. Por cada solicitud que nuestra aplicación Angular realiza al servidor, el $http
servicio Angular hará estas cosas automáticamente:
- Busque una cookie denominada XSRF-TOKEN en el dominio actual.
- Si se encuentra esa cookie, lee el valor y lo agrega a la solicitud como encabezado X-XSRF-TOKEN.
Por lo tanto, la implementación del lado del cliente se maneja automáticamente. Solo necesitamos configurar una cookie denominada XSRF-TOKEN
en el dominio actual en el lado del servidor y cuando nuestra API reciba alguna llamada del cliente, debe verificar el X-XSRF-TOKEN
encabezado y compararlo con el XSRF-TOKEN
del JWT. Si coinciden, entonces el usuario es real. De lo contrario, es una solicitud falsificada y puedes ignorarla. Este método está inspirado en el método de "doble envío de cookies".
Precaución
En realidad, todavía eres susceptible a XSS, es solo que el atacante no puede robar tu token JWT para usarlo más adelante, pero aún puede realizar solicitudes en nombre de tus usuarios usando XSS.
Ya sea que almacene su JWT en localStorage
o almacene su token XSRF en una cookie que no sea HttpOnly, XSS puede capturar ambos fácilmente. Incluso su JWT en una cookie HttpOnly puede ser capturado por un ataque XSS avanzado como el método XST .
Por lo tanto, además del método de envío doble de cookies, siempre debe seguir las mejores prácticas contra XSS, incluido el escape de contenidos. Esto significa eliminar cualquier código ejecutable que pueda provocar que el navegador haga algo que usted no desea. Normalmente, esto significa eliminar // <![CDATA[
etiquetas y atributos HTML que hacen que se evalúe JavaScript.
Leer más aquí:
- XSRF de Angular: cómo funciona
- Dónde almacenar sus JWT: cookies frente a almacenamiento web HTML5
Los tokens JWT son populares porque se utilizan como formato de token predeterminado en nuevos protocolos de autorización y autenticación como OAuth 2.0 y OpenID Connect .
Cuando el token se almacena en una cookie, el navegador lo enviará automáticamente junto con cada solicitud al mismo dominio y esto sigue siendo vulnerable a los ataques CSRF.
La autenticación de portador es uno de los esquemas de autenticación definidos en HTTP. Básicamente significa que USTED coloca el token (JWT) en el encabezado HTTP de autorización de una solicitud. El navegador NO hará esto automáticamente, por lo que no es adecuado para proteger su sitio web. Como el navegador no agrega automáticamente el encabezado a su solicitud, no es vulnerable a un ataque CSRF, lo que depende de que su información de autenticación se envíe automáticamente al dominio original.
El esquema de portador se utiliza a menudo para proteger las API web (servicios REST) que se consumen a través de llamadas AJAX o desde clientes móviles.
Ahora en 2020, simplemente almacene el token JWT en una cookie SameSite=strict
para derrotar a CSRF. Por supuesto, quédate secure
y httpOnly
también.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite