Tokens web JSON (JWT) como tokens de identificación y autenticación del usuario

70

Estoy implementando un servicio REST que requiere autenticación. No puedo almacenar ningún estado por usuario (como un token generado aleatoriamente) porque mi servicio no tiene acceso directo a una base de datos, solo a otro servicio backend.

La solución que se me ocurrió es crear un token web JSON ( JWT ) Cuando el usuario se autentica. El conjunto de notificaciones JWT contiene el ID de usuario en el campo Asunto ("sub"). Luego, el servidor cifra el conjunto de notificaciones directamente ("alg": "dir") utilizando AES GCM con una clave de 256 bits ("enc": "A256GCM") creando un JWE . La clave se genera una vez cuando se inicia el servicio y se almacena en la memoria.

Para autenticarse, el cliente envía el nombre de usuario / contraseña y el servidor responde con el token descrito anteriormente. El cliente envía ese token con cada solicitud posterior.

Cuando el cliente envía el token con las solicitudes subsiguientes, el servidor lo descifra mediante la clave y asume que la ID de usuario en el campo "sub" es la ID del usuario actual, sin más comprobaciones de autenticación. La caducidad del token se maneja mediante el campo "exp" en el conjunto de reclamaciones JWT.

La conexión entre el cliente y el servidor usará SSL / TLS, por lo que el token no tendrá fugas.

Estoy usando esta biblioteca para crear y leer JWT, ya que no confío en mí mismo para escribir el código de criptografía correcto .

Mis preguntas:

  1. ¿Es seguro el enfoque anterior? ¿Puede un atacante hacerse pasar por otro usuario manipulando el token?
  2. ¿Es el enfoque demasiado complicado? ¿El uso de MAC (en otras palabras: JWS ) en lugar del cifrado, tiene la misma seguridad? (o posiblemente más, ya que es más simple y hay menos posibilidades de cometer un error). No hay nada particularmente secreto en el conjunto de reclamaciones de JWT, y el usuario que conoce su propia identificación no importa.
  3. ¿Es mi elección del algoritmo JWE y el cifrado apropiado?
    • Para el "alg" de JWE, la biblioteca que estoy usando soporta el cifrado directo (usando la clave directamente para cifrar el conjunto de reclamaciones) y RSA (generando una nueva clave para cifrar el conjunto de reclamaciones para cada token, y cifrando el clave con una clave pública RSA). Elegí el primero porque es más fácil generar una clave simétrica que una clave RSA.
    • Para la "enc" de JWE, la biblioteca admite AES GCM y AES CBC HMAC SHA2 (con varias longitudes de bits). Elegí GCM arbitrariamente.
pregunta imgx64 11.02.2014 - 11:33
fuente

2 respuestas

50

Su enfoque básico es válido: genere el JWT cuando el usuario inicie sesión, espere que los mensajes subsiguientes lleven el JWT, confíe en el campo del asunto en el JWT en esos mensajes subsiguientes si el JWT es válido. Pero hay varias cosas que debes tener en cuenta:

  1. Como dice Daisetsu, puede usar un MAC ("alg": "HS256") ya que los MAC están diseñados específicamente para evitar la alteración de la carga útil, mientras que los algoritmos de cifrado típicamente (contraintuitivamente) son no. Sin embargo, como está utilizando AES específicamente en el modo GCM , ya obtiene un cifrado a prueba de manipulaciones ("cifrado autenticado"), por lo que no es realmente una preocupación.
  2. Al validar un JWT entrante, tenga cuidado con lo que considera válido. Por ejemplo, podría llamar a su servicio con {"sub": "me", "alg": "none"} y aunque ese JWT es válido en algún sentido, no es algo que quiera aceptar.
  3. Dado que JWT es un borrador, aún no es un estándar, podría cambiar. Si cambia lo suficiente, es posible que la biblioteca que está utilizando tenga que cambiar de manera que rompa la compatibilidad con su código.
  4. Si no puede almacenar ningún estado del lado del servidor, no tiene forma de invalidar el JWT cuando el usuario cierra la sesión. En efecto, su servicio no tiene una función de cierre de sesión, lo que puede ser un problema de seguridad, especialmente si configura el tiempo de caducidad demasiado lejos en el futuro.
  5. Si configura el tiempo de caducidad demasiado pronto, es posible que tenga un problema con los usuarios que todavía están conectados pero que no tienen un JWT válido. Esto puede ocasionar problemas incómodos de manejo de errores y flujo de trabajo del usuario.

Como usted dijo que su servidor no tiene acceso a una base de datos, asumo que el inicio de sesión real se maneja en otro lugar, tal vez el servidor backend que mencionó. No dijo cómo su servidor sabe que el usuario acaba de iniciar sesión. Dependiendo de la percepción que tenga el usuario de la relación entre su servicio y lo que sabe que inició sesión, los últimos dos puntos anteriores pueden ser discutibles.

    
respondido por el gatkin 12.02.2014 - 12:59
fuente
9

Si ninguno de los datos es confidencial, todo lo que necesita hacer es preservar la integridad de los datos. Firmar (JWS) el token debería ser suficiente para hacer eso.

Si solo está haciendo una firma, debería estar bien con HMAC SHA-256. Recuerde establecer un vencimiento del token y verificar si el usuario cerró la sesión manualmente (en ese caso, invalide el token). Una vez que toma en cuenta la caducidad y el cierre de sesión, no hay mucho de qué preocuparse (algoritmo inteligente). Las posibilidades de que alguien rompa un SHA-256 en el momento de una sola sesión (deberían) son relativamente bajas (suponiendo que sea necesario volver a realizar la autenticación en un intervalo RAZONABLE).

Como siempre con la firma, asegúrese de proporcionar el contenido que se firmará (nombre de usuario, tipo de cuenta, etc.), nunca permita que se firme ningún dato definido por el usuario o podría estar en una situación peligrosa.

Descargo de responsabilidad: Este post es estrictamente mi opinión. No estoy haciendo ninguna afirmación sobre la fiabilidad o la idoneidad de mis respuestas. Siempre debe consultar con un profesional de seguridad para discutir sus inquietudes específicas de implementación de seguridad. Esto es puramente educativo.

    
respondido por el Daisetsu 11.02.2014 - 22:48
fuente

Lea otras preguntas en las etiquetas