de forma segura utilizando JWT con protección CSRF y tokens de actualización

8

Estoy implementando JWT en mi aplicación y me gustaría hacerlos lo más seguros posible. Presentaré todo lo que estoy planeando, agradecería enormemente cualquier sugerencia en cuanto a la seguridad de esta implementación. Este es mi sitio, tengo acceso completo a todos los aspectos, tanto front-end como back-end.

Esto será un SPA, utilizando una API para acceder al back-end. Estoy usando JWT para guardar llamadas a la base de datos con cada golpe de API.

JWTs

Los JWT se almacenan en una cookie access_token . Primero se firman y luego se encriptan utilizando jose-jwt . El algoritmo de firma es HS256, el cifrado es DIR. Incluyen la ID del usuario, una caducidad exp de reclamación y varias otras reclamaciones personalizadas. Los JWT caducan en 30 minutos y la cookie de JWT caduca en 7 días.

(versión corta):

  • JWT almacenado en una cookie
  • JWT incluye ID de usuario
  • JWT firmado y luego encriptado
  • Reclamación JWT exp establecida en 30 minutos en el futuro
  • El conjunto de cookies de JWT expirará 7 días en el futuro

Protección CSRF

Los JWT incluyen una reclamación cst que almacena un token CSRF generado aleatoriamente. El token CSRF se envía en el cuerpo de la respuesta al iniciar sesión y cuando se emite un nuevo JWT. El token CSRF se almacena en el almacenamiento local del navegador. Se envía con cada solicitud y se valida con respecto al valor en el JWT.

(versión corta):

  • JWT incluye un token CSRF generado aleatoriamente
  • El token CSRF se envía al iniciar sesión y se almacena en localStorage
  • token CSRF enviado en el encabezado de solicitud de todas las solicitudes
  • El token CSRF del encabezado en comparación con el token CSRF en el JWT

Tokens de actualización

Como los JWT caducan en 30 minutos, es necesario actualizarlos. El JWT incluye una reclamación rfs que almacena un token de actualización aleatorio. Este token de actualización también se almacena en la base de datos (una tabla separada de los usuarios para permitir múltiples sesiones). Si el JWT ha caducado (según su reclamación exp ), se comprueba la base de datos para garantizar que el usuario sigue siendo válido (por ejemplo, la cuenta no se ha eliminado, la contraseña no se ha cambiado, etc.) Si el usuario es válido, se verifica el token de actualización y se genera un nuevo token JWT / CSRF y se devuelve en la respuesta. Si el usuario no es válido, access_token se devuelve con un valor arbitrario como 0 , y su vencimiento se establece en el pasado para que el navegador lo elimine. El token CSRF se devuelve vacío para que se borre de localStorage. Todos los tokens de actualización para el usuario se borran de la base de datos.

(versión corta):

  • Si JWT expiró, verifique la base de datos del usuario para verificar que el usuario aún es válido
  • SI ES VÁLIDO:
    • Compare el token de actualización con DB (suponga que coincide con el resto de esto)
    • Genere un nuevo token de actualización, sobrescriba el valor anterior en DB
    • Vuelva a emitir JWT con la nueva fecha exp
    • Pase el token de actualización y guárdelo en localStorage
  • SI NO ES VÁLIDO:
    • Borrar la cookie JWT por a) configurando un valor no válido, b) configurando la caducidad como pasada
    • Indica al navegador que borre el token CSRF de almacenamiento local
    • Borrar todos los tokens de actualización para el usuario de la base de datos

TL rápido y sucio; DR

  • Al iniciar sesión, agregue un token CSRF aleatorio al JWT.
  • Envíe ese mismo token CSRF al cliente en el cuerpo de la respuesta.
  • Almacene el token CSRF en localStorage.
  • Incluir un token de actualización en el JWT.
  • Configure la cookie JWT para que caduque después de 1 semana.
  • Establezca el reclamo de exp JWT en 30 minutos.
  • Si la reclamación JWT ha caducado, verifique el token de actualización contra la base de datos para asegurarse de que el usuario sigue siendo válido.
  • SI EL USUARIO ES VÁLIDO:
    • Emita JWT actualizado con el nuevo token CSRF y el nuevo token de actualización.
    • Establezca la caducidad de la cookie JWT en una semana en el futuro. (Vuelva a emitir la cookie, básicamente)
    • Envíe un nuevo token CSRF en el cuerpo de la respuesta, sobrescriba el valor de almacenamiento local existente.
  • SI EL USUARIO NO ES VÁLIDO:
    • Devolver la cookie JWT con el mismo nombre pero sin contenido.
    • Establezca el vencimiento de las cookies en una fecha arbitraria en el pasado.
    • Indique al navegador que borre el valor de almacenamiento local.
pregunta vaindil 13.08.2016 - 01:49
fuente

3 respuestas

7

Parece que estás mezclando diferentes tecnologías opuestas, y no dejas en claro por qué elegiste estas tecnologías y por qué controlan las amenazas contra las que intentas protegerte.

  

Los JWT se almacenan en una cookie de acceso a token. Primero se firman luego   cifrado utilizando jose-jwt.

¿Hay alguna razón por la que están encriptados? La firma se utiliza cuando desea verificar la integridad de los datos, es decir, que nadie ha sido alterado sin la clave. El cifrado se utiliza cuando desea proteger la confidencialidad de los datos, es decir, que nadie puede leerlos sin la clave. Si no hay nada en el token que el usuario final no pueda leer, no hay razón para cifrar.

  

Los JWT incluyen una reclamación cst que almacena un token CSRF generado aleatoriamente.   El token CSRF se envía en el cuerpo de la respuesta al iniciar sesión y cuando un nuevo   Se emite JWT. El token CSRF se almacena en el almacenamiento local del navegador.   Se envía con cada solicitud y se valida contra el valor en el   JWT.

Esto suena como una implementación del Double Submit Cookie CSRF control. localStorage está protegido por la Política del mismo origen que impide que otra sesión web en el navegador del usuario acceda al token.

Asegúrese de que el token CSRF tenga al menos 128 bits de entropía.

  

Como los JWT caducan en 30 minutos, es necesario actualizarlos. los   JWT incluye un reclamo de rfs que almacena un token de actualización aleatorio. Esta   el token de actualización también se almacena en la base de datos (una tabla separada de los usuarios para   permitir múltiples sesiones). Si el JWT está vencido (basado en su exp   reclamación), se comprueba la base de datos para garantizar que el usuario sigue siendo válido (por ejemplo,   cuenta no eliminada, contraseña no cambiada, etc.). Si el usuario es   válido, el token de actualización se verifica y un nuevo token JWT / CSRF son   generado y devuelto en la respuesta.

Aquí es donde las cosas se mezclan. Su modelo de seguridad debe decidir entre sesiones del lado del cliente o sesiones del lado del servidor. JWTs se emplean generalmente para los primeros. Es decir, si tiene un token en el cliente firmado por una clave que solo está disponible para el servidor, entonces su aplicación debe confiar en que la presencia de este token denota una sesión válida en caso de que no haya caducado y que la firma sea válida. p>

La desventaja de este método es que es difícil revocar tokens. Si una cuenta de usuario se ve comprometida y un usuario cambia su contraseña, las sesiones de los atacantes permanecerán activas durante 30 minutos porque aún tienen un token válido, caducado y firmado.

La solución para esto es implementar sesiones del lado del servidor en su lugar. Por ejemplo, realiza un seguimiento de las sesiones en una tabla de la base de datos, lo que significa que se pueden desconectar instantáneamente eliminando la fila de la base de datos. El token de sesión puede ser una cadena aleatoria de entropía de 128 bits, suministrada como una cookie del lado del cliente y almacenada como hash con el lado del servidor SHA-256 para mitigar cualquier fuga de datos de su base de datos. Siempre puede enviar una fecha de caducidad de texto sin formato con su cookie, para que el cliente sepa que necesita actualizar el token. p.ej. una cookie HttpOnly para el token, y una cookie no HttpOnly que contiene la caducidad para que el JavaScript del lado del cliente pueda leerla. Las cookies de HttpOnly pueden ayudar a mitigar el impacto de una falla XSS.

Por lo tanto, si está realizando un seguimiento de las sesiones del lado del servidor, hay pocas ventajas de tener un lado del cliente JWT firmado. Un código adicional significa más superficie de ataque y más posibilidades de que se introduzcan vulnerabilidades en el código excedente. La complejidad en una aplicación a menudo es inversa a la seguridad.

Si está utilizando Double Submit Cookie en combinación con una sesión del lado del servidor para el estado de la sesión, es aconsejable utilizar una cookie diferente para el token CSRF. Esto le permitirá agregar el token CSRF como encabezado usando el código del lado del cliente sin arriesgar su token de identificador de sesión. Tenga en cuenta que si está configurando encabezados personalizados y no implementando CORS, entonces esto puede mitigar algo la CSRF . Sin embargo, también se recomienda usar un token, ya que las tecnologías como Flash tienden a interrumpir la seguridad del navegador (Flash significa que se ejecuta más código, más código da más superficie de ataque, más código significa más posibilidades de vulnerabilidades).

    
respondido por el SilverlightFox 21.08.2016 - 21:26
fuente
2

Agregación de comentarios:

  • JWT como credencial de portador en una aplicación de una sola página que habla con una API del lado del servidor sobre ajax tiene sentido.
  • El uso de cookies en una aplicación de una sola página no tiene sentido. Si todas las solicitudes al servidor cuelgan de botella a través de una función ajax, esa función puede incluir JWT en un encabezado. Si no hay cookies, entonces no hay CSRF, porque las solicitudes de los marcos de ataque no pasarán por la función ajax
  • El uso de scripts de terceros es, por supuesto, generalizado, pero sin embargo es un gran riesgo para la seguridad. Los scripts de terceros operan dentro del mismo contexto de javascript y DOM y pueden ver todo el DOM. Si son maliciosos, hay muchas, muchas opciones de ataque. Si es posible, elimine los scripts de terceros o asegúrese de que se verifiquen, utilizando la integridad de los sub-recursos o algún otro medio (por ejemplo, supervíselos para detectar cambios).
  • localStorage sigue la misma política de origen y puede tratarse como un caché de cliente para DOM o datos de autorización. En un SPA, el JWT se puede mantener en localStorage, porque sigue el mismo modelo de seguridad que el DOM.
  • Se puede guardar un token de actualización en el JWT
  • Es difícil hacer comentarios sobre el tiempo de caducidad y actualización de JWT en el resumen. Es importante encontrar el equilibrio adecuado entre seguridad y facilidad de uso, no exigir a los usuarios que superen los obstáculos a menos que haya una buena razón, y brindarles a los usuarios la seguridad adecuada en caso de que tengan alguna duda.

Algunas otras cosas que hacer:

  • Exigir https y usar encabezados de protocolo de recursos relacionados, como x-frame-options, seguridad de transporte estricta y política de seguridad de contenido
  • Mantenga algunos metadatos de la versión particular de la aplicación de página única en el JWT, y requiera una actualización después de la actualización de la aplicación
  • Mantener los metadatos del cliente en particular en el JWT. No permita el uso de un navegador de escritorio JWT desde un navegador móvil.
  • Tiene la capacidad del servidor para revocar todos los JWT pendientes y actualizar tokens asociados con un usuario. Si un usuario tenía JWT y tokens de actualización vinculados a su teléfono y computadora de escritorio, y le dice que perdió su teléfono, es probable que desee invalidar sus JWT de teléfono y de escritorio y actualizar tokens.
  • Tener una autorización sólida a nivel de objeto / operación en la API del servidor, es decir, verificar la integridad de JWT, confirmar que la autorización que contiene no ha sido revocada y luego verificar que las reclamaciones que incluye proporcionen el acceso adecuado a la API. antes de realizar cualquier operación de API.
respondido por el Jonah Benton 21.08.2016 - 20:05
fuente
1

Esto me suena bastante bien (la solución CSRF también es linda) hasta la parte del token de actualización.

Una de las ventajas que veo en un sistema basado en JWT es que los tokens de acceso caducan regularmente. Esto significa que un token de acceso JWT comprometido solo le da acceso a un atacante por un período de minutos u horas.

Si incluye el token de actualización en el JWT, un atacante que comprometa al JWT puede usarlo fácilmente para actualizarse, lo que hace que no tenga una fecha de caducidad efectiva.

Un token de acceso no debería poder otorgar un token de acceso nuevo. Solo un token de actualización (o autenticación completa) debe poder otorgar un token de acceso nuevo.

    
respondido por el ProdigySim 06.12.2017 - 03:18
fuente

Lea otras preguntas en las etiquetas