Manejo de renovación de token / caducidad de sesión en una API RESTful

14

Estoy creando una API RESTful que usa tokens JWT para la autenticación del usuario (emitida por un punto final login y enviada en todos los encabezados posteriormente), y los tokens deben actualizarse después de un período de tiempo fijo (invocar un renew endpoint, que devuelve un token renovado).

Es posible que la sesión de la API de un usuario se convierta en inválida antes de que caduque el token, por lo tanto, todos mis puntos finales se inician al verificar que: 1) el token sigue siendo válido y 2) la sesión del usuario todavía es válida. No hay forma de invalidar directamente el token, porque los clientes lo almacenan localmente.

Por lo tanto, todos mis puntos finales deben indicar a mis clientes dos posibles condiciones: 1) que es hora de renovar el token o 2) que la sesión se ha vuelto inválida y ya no se les permite acceder al sistema. Puedo pensar en dos alternativas para que mis puntos finales señalen a sus clientes cuando se produce una de las dos condiciones (suponiendo que los clientes pueden adaptarse a cualquiera de las opciones):

  1. Devuelva un código http 401 (no autorizado) si la sesión no es válida o devuelva un código 412 (condición previa fallida) cuando el token haya caducado y sea el momento de llamar al punto final renew , que devolverá un 200 (ok) código.
  2. Devuelve 401 para indicar que la sesión no es válida o que el token ha caducado. En este caso, el cliente llamará inmediatamente al punto final renew , si devuelve 200, entonces el token se actualizará, pero si renew también devuelve 401, eso significa que el cliente está fuera del sistema.

¿Cuál de las dos alternativas anteriores recomendarías? ¿Cuál sería más estándar, más fácil de entender y / o más RESTful? ¿O recomendarías un enfoque completamente diferente? ¿Ve algún problema obvio o riesgos de seguridad con alguna de las opciones? Puntos adicionales si su respuesta incluye referencias externas que apoyan su opinión.

ACTUALIZAR

Chicos, céntrese en la pregunta real: ¿cuál de las dos alternativas de código http para señalar una renovación / invalidación de sesión es la mejor? No me importa el hecho de que mi sistema use JWT y sesiones del lado del servidor, esa es una peculiaridad de mi API para reglas comerciales muy específicas, y no la parte para la que busco ayuda;)

    
pregunta Óscar López 17.12.2016 - 17:02

3 respuestas

16

Esto suena como un caso de autenticación frente a autorización .

Los JWT son reclamos firmados criptográficamente sobre el originador de una solicitud. Un JWT puede contener notificaciones como "Esta solicitud es para el usuario X" y "El usuario X tiene roles de administrador". Obtener y proporcionar esta prueba mediante contraseñas, firmas y TLS es el dominio de autenticación , lo que demuestra que usted es quien dice ser.

Lo que esos reclamos significan a su servidor (lo que los usuarios y roles específicos pueden hacer) es el problema de autorización . La diferencia entre los dos se puede describir con dos escenarios. Supongamos que Bob quiere entrar en la sección de almacenamiento restringido del almacén de su compañía, pero primero debe tratar con un guardia llamado Jim.

Escenario A - Autenticación

  • Bob: "Hola Jim, me gustaría ingresar al almacenamiento restringido".
  • Jim: "¿Tienes tu placa?"
  • Bob: "No, lo olvidé"
  • Jim: "Lo siento amigo, no hay entrada sin credencial".

Escenario B - Autorización

  • Bob: "Hola Jim, me gustaría ingresar al almacenamiento restringido. Aquí está mi placa".
  • Jim: "Oye Bob, necesitas la autorización de nivel 2 para ingresar aquí. Lo siento".
Los tiempos de caducidad de

JWT son dispositivos de autenticación que se utilizan para evitar que otros los roben. Si todos sus JWT tienen un tiempo de expiración de cinco minutos, no es tan importante si se los roban porque rápidamente se volverán inútiles. Sin embargo, la regla de "caducidad de sesión" que discute suena como un problema de autorización. Algunos cambios en el estado significan que el usuario X ya no puede hacer algo que solía hacer. Por ejemplo, el usuario Bob podría haber sido despedido, no importa que su credencial diga que es Bob, porque simplemente ser Bob ya no le otorga ninguna autoridad con la compañía.

Estos dos casos tienen distintos códigos de respuesta HTTP: 401 Unauthorized y 403 Forbidden . El código 401 denominado desafortunadamente es para problemas de autenticación, como credenciales faltantes, caducadas o revocadas. 403 es para autorización, donde el servidor sabe exactamente quién eres, pero no puedes hacer lo que intentas hacer. En el caso de que se elimine la cuenta de un usuario, intentar hacer algo con un JWT en un punto final daría como resultado una respuesta 403 Prohibida. Sin embargo, si el JWT ha caducado, el resultado correcto sería 401 No autorizado.

Un patrón JWT común es tener tokens de "larga vida" y "de corta duración". Los tokens de larga duración se almacenan en el cliente como tokens de corta duración, pero tienen un alcance limitado y solo se utilizan con su sistema de autorización para obtener tokens de corta duración. Los tokens de larga duración, como su nombre lo indica, tienen períodos de caducidad muy largos; puede usarlos para solicitar tokens nuevos durante días o semanas. Los tokens de vida corta son los tokens que estás describiendo, usados con tiempos de vencimiento muy cortos para interactuar con tu sistema. Los tokens de larga duración son útiles para implementar la funcionalidad Remember Me, por lo que no es necesario que proporcione su contraseña cada cinco minutos para obtener un nuevo token de corta duración.

El problema de "invalidación de sesión" que está describiendo suena similar a intentar invalidar un JWT de larga duración, ya que los de corta duración rara vez se almacenan en el lado del servidor mientras que los de larga duración se rastrean en caso de que deban ser revocados. En un sistema de este tipo, intentar adquirir credenciales con un token de larga vida revocado resultaría en 401 No autorizado, porque el usuario podría técnicamente ser capaz de adquirir credenciales, pero el token que está usando no es adecuado para la tarea. Luego, cuando el usuario intenta adquirir un nuevo token de larga duración con su nombre de usuario y contraseña, el sistema podría responder con 403 Prohibido si son expulsados del sistema.

    
respondido por el Jack 18.12.2016 - 00:40
12

Su sesión de API es una cosa que no debería existir en un mundo RESTful en absoluto. Las operaciones REST se supone que son sin estado, la sesión contiene el estado y, por lo tanto, no tiene lugar en un mundo RESTful.

El JWT debe ser su única forma de determinar si un usuario aún es elegible para acceder a un punto final o no. Una sesión no debería desempeñar ningún papel en ella. Si lo hace, no tienes una API RESTful.

Cuando eliminas la sesión por completo, lo que si estás buscando una API RESTful deberías hacerlo, y solo usas el JWT como un factor de autenticación, un usuario está autorizado para usar tu punto final o no, en cuyo caso el% El código de respuesta de 401 Unauthorized es apropiado, y debe llamar al punto final renew con grant_type=refresh_token o cualquier identificación de renovación que esté utilizando.

Actualizar:

A partir del comentario, parece que el flujo de validación del JWT que está utilizando actualmente no es correcto. Se supone que la validación debe ser así:

  Client        RESTful API      JWT Issuer
     |              |                |
     |----- 1. ---->|                | 
     |              |------ 2. ----->|-----
     |              |                | 3. |
     |              |<----- 4. ------|<----
-----|<---- 5. -----|                |
| 6. |              |                |
---->|----- 7. ---->|                |
     |              |------ 8. ----->|-----
     |              |                | 9. |
     |              |<----- 10. -----|<----
     |              |                |
     |              |------          |
     |              | 11. |          |
     |<---- 12. ----|<-----          |
     |              |                |
     .              .                .

1. Ask RESTful API for a JWT using login endpoint.
2. Ask Issuer to create a new JWT.
3. Create JWT.
4. Return JWT to the RESTful API.
5. Return JWT to Client.
6. Store JWT to append it to all future API requests.
7. Ask for data from API providing JWT as authorization.
8. Send JWT to Issuer for verification.
9. Issuer verifies JWT.
10. Issuer returns 200 OK, verification successful.
11. Retrieve and format data for Client.
12. Return data to Client.

El servidor, RESTful API , debe verificar la validez del token que se está enviando como Autorización. Eso no es responsabilidad del Client . Parece que actualmente no estás haciendo esto. Implemente la verificación del JWT de esta manera y no necesitará ninguna sesión.

    
respondido por el Andy 17.12.2016 - 18:23
1

Por lo tanto, confesaré que no tiene mucho sentido que me preocupe cuál es el enfoque que más RESTABLEZCA cuando ya está rompiendo las convenciones REST con la sesión, pero entiendo que satisfizo sus requisitos comerciales.

Desde un punto de vista REST, el cliente está autenticado o no. A la arquitectura no le importa mucho el motivo (es decir, inyectar un estado innecesario), por lo que para responder a su pregunta principal, no tendría un punto final renovado. Un cliente registrado simplemente siempre enviará su JWT y el servidor siempre lo validará y lo aceptará enviando el código de éxito apropiado basado en la acción 200, 201, etc.) o lo rechazará con un 401 o 403, según corresponda.

Ahora, el JWT se asociará con una cuenta de algún tipo. Esa cuenta puede estar bloqueada o limitada o lo que sea, por lo que el token en sí puede ser válido, pero la acción aún puede ser rechazada en otro lugar. Si el caso es que la cuenta de usuario está bloqueada debido a las reglas comerciales, entonces sigue siendo un 401 o 403, dependiendo de la cantidad de información que desee darle al cliente (diferentes empresas tienen diferentes opiniones al respecto).

Finalmente, si está afirmando que la cuenta puede estar desbloqueada y es válida pero el JWT solo necesita ser revocado, entonces AÚN me quedaría con el 401 o el 403 y mantendría algo así como una Lista de revocación de certificados de JWT no válidos que pueda coloque uno, siempre que se limpie por sí solo cuando el JWT haya caducado (la mayoría de las bases de datos tienen una forma de hacerlo o puede tener eventos en el código de la aplicación).

    
respondido por el Paul 18.12.2016 - 00:50

Lea otras preguntas en las etiquetas