¿Es seguro almacenar un JWT en localStorage con ReactJS?
Actualmente estoy creando una aplicación de una sola página usando ReactJS.
Leí que una de las razones para no usarlo localStorage
es por las vulnerabilidades XSS.
Dado que React escapa a todas las entradas del usuario, ¿sería seguro usarlo ahora localStorage
?
En la mayoría de las aplicaciones modernas de una sola página, tenemos que almacenar el token en algún lugar del lado del cliente (el caso de uso más común es mantener al usuario conectado después de actualizar la página).
Hay un total de 2 opciones disponibles: Almacenamiento web (almacenamiento de sesión, almacenamiento local) y una cookie del lado del cliente. Ambas opciones son muy utilizadas, pero esto no significa que sean muy seguras.
Tom Abbott resume bien la seguridad de sessionStorage y localStorage de JWT :
Se puede acceder al almacenamiento web (localStorage/sessionStorage) a través de JavaScript en el mismo dominio. Esto significa que cualquier JavaScript que se ejecute en su sitio tendrá acceso al almacenamiento web y, debido a esto, puede ser vulnerable a ataques de secuencias de comandos entre sitios (XSS) . XSS, en pocas palabras, es un tipo de vulnerabilidad donde un atacante puede inyectar JavaScript que se ejecutará en su página. Los ataques XSS básicos intentan inyectar JavaScript a través de entradas de formulario, donde el atacante ingresa
<script>alert('You are Hacked');</script>
un formulario para ver si el navegador lo ejecuta y puede ser visto por otros usuarios.
Para evitar XSS, la respuesta común es escapar y codificar todos los datos que no sean de confianza. ¡React (principalmente) hace eso por ti! Aquí hay una gran discusión sobre cuánta protección contra vulnerabilidades XSS es responsable de React .
¡Pero eso no cubre todas las posibles vulnerabilidades! Otra amenaza potencial es el uso de JavaScript alojado en CDN o infraestructura externa .
Aquí está Tom otra vez:
Las aplicaciones web modernas incluyen bibliotecas de JavaScript de terceros para pruebas A/B, análisis de embudo/mercado y anuncios. Usamos administradores de paquetes como Bower para importar el código de otras personas a nuestras aplicaciones.
¿Qué pasa si sólo uno de los scripts que utiliza está comprometido? Se puede incrustar JavaScript malicioso en la página y el almacenamiento web se ve comprometido. Estos tipos de ataques XSS pueden afectar el almacenamiento web de todos los que visitan su sitio, sin su conocimiento. Probablemente esta sea la razón por la que muchas organizaciones recomiendan no almacenar nada de valor ni confiar en ninguna información en el almacenamiento web. Esto incluye identificadores de sesión y tokens.
Por lo tanto, mi conclusión es que, como mecanismo de almacenamiento, Web Storage no aplica ningún estándar seguro durante la transferencia . Quien lea Web Storage y lo utilice debe hacer su debida diligencia para asegurarse de enviar siempre el JWT a través de HTTPS y nunca de HTTP.
Básicamente, está bien almacenar su JWT en su almacenamiento local.
Y creo que esta es una buena manera. Si estamos hablando de XSS, XSS usando CDN, también existe un riesgo potencial de obtener el inicio de sesión/contraseña de su cliente. Almacenar datos en un almacenamiento local evitará al menos los ataques CSRF.
Debes ser consciente de ambos y elegir lo que quieras. Ambos ataques no son todo lo que necesita tener en cuenta, solo recuerde: TODA SU APLICACIÓN ES TAN SEGURA COMO EL PUNTO MENOS SEGURO DE SU APLICACIÓN.
Una vez más, el almacenamiento está bien, ser vulnerable a XSS, CSRF,... no lo es
Sé que esta es una vieja pregunta, pero según lo que dijo @ mikejones1477, las bibliotecas y marcos frontales modernos escapan del texto que le brinda protección contra XSS. La razón por la que las cookies no son un método seguro para usar credenciales es que las cookies no impiden CSRF cuando localStorage lo hace (recuerde también que JavaScript también puede acceder a las cookies, por lo que XSS no es el gran problema aquí), esta respuesta resume por qué .
La razón por la que almacenar un token de autenticación en el almacenamiento local y agregarlo manualmente a cada solicitud protege contra CSRF es esa palabra clave: manual. Dado que el navegador no envía automáticamente ese token de autenticación, si lo visito
evil.example
y logra enviar un POSThttp://example.com/delete-my-account
, no podrá enviar mi token de autenticación, por lo que se ignora la solicitud.
Por supuesto, httpOnly es el santo grial, pero no puede acceder desde reaccionarjs ni desde ningún marco js. Además, todavía tiene una vulnerabilidad CSRF. Mi recomendación sería el almacenamiento local o, si desea utilizar cookies, asegúrese de implementar alguna solución a su problema CSRF como lo hace Django .
Con respecto a las CDN, asegúrese de no estar utilizando ninguna CDN extraña, por ejemplo, una CDN como la proporcionada por Google o la de bootstrap, que sea mantenida por la comunidad y que no contenga código malicioso; si no está seguro, puede revisarla.
Me preocupan todas las respuestas que sugieren no almacenar en el almacenamiento local, ya que es susceptible a un ataque XSS o una biblioteca maliciosa. Algunos de ellos incluso entran en discusiones largas, aunque la respuesta es bastante pequeña y sencilla, a lo que llegaré en breve.
Sugerir eso equivale a decir “No uses una sartén para cocinar tu comida porque si una noche terminas borracho y decides freír, terminarás quemándote a ti mismo y a tu casa”. Si el jwt se filtra debido a un ataque XSS o una biblioteca maliciosa, entonces el propietario del sitio tiene un problema mayor: su sitio es susceptible a ataques XSS o está utilizando una biblioteca maliciosa.
La respuesta: si está seguro de que su sitio no tiene esas vulnerabilidades, hágalo.
Ref: https://auth0.com/docs/security/data-security/token-storage#browser-local-storage-scenarios
Una cosa a tener en cuenta es si los JWT son:
- De origen (es decir, simplemente para acceder a los comandos de su propio servidor)
- Tercero (es decir, un JWT para Google, Facebook, Twitter, etc.)
Si el JWT es propio:
Entonces no importa mucho si almacena el JWT en un almacenamiento local o en una cookie segura (es decir HttpOnly
, SameSite=strict
y secure
) [suponiendo que su sitio ya esté usando HTTPS, lo cual debería ser así].
Esto se debe a que, suponiendo que un ataque XSS tenga éxito (es decir, un atacante pudo insertar código Javascript a través de una dependencia JS que ahora se ejecuta en todos los navegadores de los visitantes), de todos modos se acabó el juego; Todos los comandos que debían estar protegidos por las "verificaciones de token JWT" ahora pueden ser ejecutados por el atacante simplemente haciendo que el script que insertaron en el JS de la interfaz llame a todos los puntos finales necesarios. Aunque no pueden leer el token JWT en sí (debido al indicador de solo http de la cookie), no importa porque simplemente pueden enviar todos los comandos necesarios y el navegador enviará felizmente el token JWT junto con esos comandos. .
Ahora bien, si bien se puede decir que la situación del ataque XSS ha terminado en cualquier sentido (ya sea almacenamiento local o cookie segura), las cookies siguen siendo un poco mejores, porque el atacante sólo puede ejecutar los ataques si/cuando el usuario tiene el sitio web. abrir en su navegador.
Esto provoca las siguientes "molestias" para el atacante:
- "¡Mi inyección XSS funcionó! Bien, es hora de recopilar datos privados sobre mi jefe y usarlos como chantaje. ¡Maldita sea! Él solo inicia sesión mientras yo estoy aquí en el trabajo. Tendré que preparar todo mi código con anticipación". , y ejecutarlo dentro de los tres minutos que esté allí, en lugar de tener que husmear en sus datos en la plataforma de una manera más gradual/exploratoria".
- "¡Mi inyección XSS funcionó! ¡Ahora puedo cambiar el código para enviarme todas las transferencias de Bitcoin! No tengo ningún objetivo en particular en mente, así que no necesito esperar a nadie. Pero, ojalá pudiera hacerlo. acceder al token JWT en sí, de esa manera podría recolectarlos todos silenciosamente y luego vaciar las billeteras de todos a la vez. Con estos JWT protegidos por cookies, es posible que solo pueda secuestrar a unas pocas docenas de visitantes antes de que los desarrolladores se enteren y suspendan las transferencias. ..."
- "¡Mi inyección XSS funcionó! Esto me dará acceso incluso a los datos que solo los administradores pueden ver. Hmmm, desafortunadamente tengo que hacer todo a través del navegador del usuario. No estoy seguro de que haya una forma realista de descargarlos". Archivos de 3 GB usando esto; comienzo la descarga, pero hay problemas de memoria, ¡y el usuario siempre cierra el sitio antes de terminar! Además, me preocupa que alguien pueda detectar retransferencias de este tamaño del lado del cliente".
Si el JWT es de terceros:
En este caso, realmente depende de lo que los JWT de terceros permitan hacer al titular.
Si todo lo que hacen es permitir que alguien "acceda a la información básica del perfil" de cada usuario, entonces no es tan malo que los atacantes puedan acceder a ella; Es posible que se filtren algunos correos electrónicos, pero el atacante probablemente podría obtenerlos de todos modos navegando a la "página de cuenta" del usuario donde se muestran esos datos en la interfaz de usuario. (tener el token JWT solo les permite evitar las "molestias" enumeradas en la sección anterior)
Si, en cambio, los JWT de terceros le permiten hacer cosas más importantes, como tener acceso completo a sus datos de almacenamiento en la nube, enviar mensajes en plataformas de terceros, leer mensajes privados en plataformas de terceros, etc., entonces tener acceso a los JWT es sustancialmente peor que simplemente poder "enviar comandos autenticados".
Esto se debe a que, cuando el atacante no puede acceder al JWT real, debe enrutar todos los comandos a través de su servidor externo. Esto tiene las siguientes ventajas:
Comandos limitados: debido a que todos los comandos pasan por su servidor, los atacantes solo pueden ejecutar el subconjunto de comandos para los cuales su servidor fue creado. Por ejemplo, si su servidor solo lee/escribe desde una carpeta específica en el almacenamiento en la nube de un usuario, entonces el atacante tiene la misma limitación.
Detección más sencilla: debido a que todos los comandos pasan por su servidor, es posible que pueda notar (a través de registros, aumento repentino en los comandos, etc.) que alguien ha desarrollado un ataque XSS. Esto le permite potencialmente parcharlo más rápidamente. (Si tuvieran los JWT, podrían realizar llamadas silenciosamente a plataformas de terceros, sin tener que ponerse en contacto con sus servidores en absoluto)
Más formas de identificar al atacante: debido a que los comandos pasan a través de su servidor, usted sabe exactamente cuándo se generan los comandos y qué dirección IP se utiliza para generarlos. En algunos casos, esto podría ayudarle a identificar quién está realizando los ataques. La dirección IP es la forma más obvia, aunque es cierto que la mayoría de los atacantes capaces de realizar ataques XSS serían lo suficientemente conscientes como para utilizar un proxy.
Un enfoque de identificación más avanzado podría ser, por ejemplo, tener un mensaje emergente especial que sea único para cada usuario (o, al menos, dividido en grupos), de tal naturaleza que el atacante (cuando carga el sitio web desde su propia cuenta) verá ese mensaje e intentará ejecutar un nuevo comando basado en él. Por ejemplo, podría vincular a una "publicación de blog de desarrollador falsa" que hable sobre alguna "nueva API" que está presentando, que permite a los usuarios acceder a aún más datos privados; La parte engañosa es que la URL de esa "nueva API" es diferente según el usuario que ve la publicación del blog , de modo que cuando se intenta usar la API (contra la víctima), se sabe exactamente quién lo hizo. Por supuesto, esto se basa en la idea de que el atacante tiene una "cuenta real" en el sitio junto con la víctima, y podría verse tentado/engañado por este tipo de enfoque (por ejemplo, no funcionará si el atacante sabe que estás sobre él), pero es un ejemplo de cosas que puedes hacer cuando puedes interceptar todos los comandos autenticados.
Control más flexible: digamos que acaba de descubrir que alguien implementó un ataque XSS en su sitio.
Si los atacantes tienen JWT de terceros, sus opciones son limitadas: debe deshabilitar/restablecer globalmente su configuración OAuth/JWT para todas las plataformas de terceros. Esto causa graves interrupciones mientras intentas descubrir el origen del ataque XSS, ya que nadie puede acceder a nada desde esas plataformas de terceros. (incluido su propio servidor, ya que los tokens JWT que pudo haber almacenado ahora no son válidos)
Si los tokens JWT están protegidos en cookies solo http, tiene más opciones: simplemente puede modificar su servidor para "filtrar" cualquier lectura/escritura que sea potencialmente peligrosa. En algunos casos, este "filtrado" es un proceso rápido y sencillo, que permite que su sitio continúe en modo "solo lectura"/"limitado" sin interrumpir todo; en otros casos, las cosas pueden ser lo suficientemente complejas como para que no valga la pena confiar en el código de filtro por motivos de seguridad. Sin embargo, el punto es que tienes más opciones.
Por ejemplo, tal vez no esté seguro de que alguien haya implementado un ataque XSS, pero lo sospecha. En este caso, es posible que no desee invalidar los tokens JWT de cada usuario (incluidos los que su servidor utiliza en segundo plano) simplemente por sospecha de un ataque XSS (depende de su nivel de sospecha). En su lugar, puedes simplemente "hacer que las cosas sean de sólo lectura por un tiempo" mientras analizas el problema más de cerca. Si resulta que no pasa nada, simplemente puede activar un interruptor y volver a habilitar las escrituras, sin que todos tengan que volver a iniciar sesión y demás.
De todos modos, debido a estos cuatro beneficios, he decidido almacenar siempre los JWT de terceros en "cookies seguras" en lugar de en el almacenamiento local. Si bien actualmente los JWT de terceros tienen alcances muy limitados (de modo que no es tan importante si son robados), es una buena prueba de futuro hacer esto, en caso de que desee que mi aplicación solicite acceso a funcionalidades más privilegiadas. en el futuro (por ejemplo, acceso al almacenamiento en la nube del usuario).
Nota: Los cuatro beneficios anteriores (para almacenar JWT de terceros en cookies seguras) también pueden aplicarse parcialmente a los JWT propios, si los JWT se utilizan como autenticación por múltiples servicios backend y los dominios/direcciones IP de estos otros servidores. /servicios son de conocimiento público. En este caso, son "equivalentes a plataformas de terceros", en el sentido de que las "cookies de sólo http" restringen al atacante XSS el envío de comandos directos a esos otros servidores, aportando parte de los beneficios de los cuatro puntos anteriores. (No es exactamente lo mismo, ya que al menos controlas esos otros servidores, por lo que puedes activar el modo de solo lectura para ellos y demás, pero en general seguirá siendo más trabajo que hacer esos cambios en un solo lugar)