Seguridad API REST Token almacenado vs JWT vs OAuth

104

Todavía estoy tratando de encontrar la mejor solución de seguridad para proteger la API REST, porque la cantidad de aplicaciones móviles y API aumenta cada día.

He intentado diferentes formas de autenticación, pero todavía tengo algunos malentendidos, por lo que necesito el consejo de alguien más experimentado.

Déjame decirte cómo entiendo todo esto. Si entiendo algo incorrectamente, avíseme.

En la medida en que la API REST no tiene estado y la WEB en general, debemos enviar algunos datos de autenticación en cada solicitud (cookies, token ...). Conozco tres mecanismos ampliamente utilizados para autenticar usuarios

  1. Token con HTTPS. He usado este enfoque muchas veces, es lo suficientemente bueno con HTTPS. Si el usuario proporciona la contraseña y el inicio de sesión correctos, recibirá un token en respuesta y lo usará para otras solicitudes. La ficha es generada por el servidor y almacenada, por ejemplo, en la tabla separada o la misma donde se almacena la información del usuario. Entonces, para cada solicitud, el servidor verifica si el usuario tiene un token y es el mismo que en la base de datos. Todo es bastante sencillo.

  2. Token JWT. Este token es autodescriptivo, contiene toda la información necesaria sobre el token en sí, el usuario no puede cambiar, por ejemplo, la fecha de vencimiento o cualquier otro reclamo, porque este token es generado (firmado) por el servidor con una palabra clave secreta. Esto también está claro. Pero un gran problema, personalmente para mí, es cómo invalidar el token.

  3. OAuth 2. No entiendo por qué este enfoque debería usarse cuando la comunicación se establece directamente entre el servidor y el cliente. Según tengo entendido, el servidor OAuth se usa para emitir tokens con un alcance restringido para permitir que otras aplicaciones accedan a la información del usuario sin almacenar la contraseña y el inicio de sesión. Esta es una gran solución para las redes sociales, cuando el usuario desea registrarse en alguna página, el servidor puede solicitar permisos para obtener información del usuario, por ejemplo de Twitter o Facebook, y llenar los campos de registro con datos del usuario, etc.

Considere el cliente móvil para la tienda en línea.

Primera pregunta, ¿debería preferir JWT sobre el primer tipo de token? En la medida en que necesite un usuario de inicio de sesión / cierre de sesión en el cliente móvil, necesito almacenar un token en algún lugar o, en el caso de JWT, el token debe invalidarse al cerrar sesión. Se utilizan diferentes enfoques para invalidar el token, uno de los cuales es crear una lista de tokens no válida (lista negra). Hmm La tabla / archivo tendrá un tamaño mucho mayor que si el token se almacenara en la tabla y se asociara con el usuario, y simplemente se eliminara al cerrar sesión.

Entonces, ¿cuáles son los beneficios del token JWT?

Segunda pregunta sobre OAuth, ¿debería usarla en caso de comunicación directa con mi servidor? ¿Cuál es el propósito de una capa más entre el cliente y el servidor solo para emitir token, pero la comunicación no será con el servidor oauth sino con el servidor principal? Según tengo entendido, el servidor OAuth es responsable solo de otorgar permisos de aplicaciones de terceros (tokens) para acceder a la información privada del usuario. Pero mi aplicación de cliente móvil no es de terceros.

CROSP
fuente
Gracias, me preguntaba esto recientemente. Fui con la gestión de sesión (Beaker) y eliminé los tokens de sesión después de una hora. Oauth no parecía el adecuado.
JasTonAChair

Respuestas:

86

Considere el primer caso. Cada cliente obtiene una identificación aleatoria que dura la duración de la sesión, que podría ser de varios días si lo desea. Luego almacena la información relevante para esa sesión en algún lado del servidor. Podría estar en un archivo o una base de datos. Supongamos que pasa la identificación a través de una cookie pero podría usar la URL o un encabezado HTTP.

ID de sesión / Cookies

Pros:

  • Fácil de codificar tanto el cliente como el servidor.
  • Fácil de destruir una sesión cuando alguien cierra la sesión.

Contras:

  • El lado del servidor periódicamente necesita eliminar las sesiones caducadas donde el cliente no cerró sesión.
  • Cada solicitud HTTP requiere una búsqueda en el almacén de datos.
  • Los requisitos de almacenamiento aumentan a medida que más usuarios tienen sesiones activas.
  • Si hay varios servidores HTTP front-end, todos los datos de sesión almacenados deben ser accesibles. Esto podría ser un poco más trabajo que almacenarlo en un servidor. Los problemas más importantes son que el almacén de datos se convierte en un único punto de falla y puede convertirse en un cuello de botella.

Tokens web JSON (JWT)

En el segundo caso, los datos se almacenan en un JWT que se pasa en lugar de en el servidor.

Pros:

  • Los problemas de almacenamiento del lado del servidor se han ido.
  • El código del lado del cliente es fácil.

Contras:

  • El tamaño de JWT podría ser mayor que una ID de sesión. Podría afectar el rendimiento de la red, ya que se incluye con cada solicitud HTTP.
  • Los datos almacenados en el JWT son legibles por el cliente. Esto puede ser un problema.
  • El lado del servidor necesita código para generar, validar y leer JWT. No es difícil, pero hay una pequeña curva de aprendizaje y la seguridad depende de ello.

    Cualquiera que obtenga una copia de la clave de firma puede crear JWT. Es posible que no sepa cuándo sucede esto.

    Hubo (¿hay?) Un error en algunas bibliotecas que aceptaba cualquier JWT firmado con el algoritmo "ninguno" para que cualquiera pudiera crear JWT en los que el servidor confiara.

  • Para revocar un JWT antes de que caduque, debe usar una lista de revocación. Esto lo lleva de regreso a los problemas de almacenamiento del lado del servidor que intentaba evitar.

OAuth

A menudo, OAuth se usa para autenticación (es decir, identidad), pero se puede usar para compartir otros datos, como una lista de contenido que el usuario ha comprado y tiene derecho a descargar. También se puede usar para otorgar acceso para escribir en los datos almacenados por el tercero. Puede usar OAuth para autenticar a los usuarios y luego usar el almacenamiento del lado del servidor o JWT para los datos de la sesión.

Pros:

  • No hay código para que los usuarios se registren o restablezcan su contraseña.
  • No hay código para enviar un correo electrónico con un enlace de validación y luego validar la dirección.
  • Los usuarios no necesitan aprender / escribir otro nombre de usuario y contraseña.

Contras:

  • Depende de un tercero para que sus usuarios utilicen su servicio. Si su servicio deja de funcionar o lo descontinúan, entonces necesita resolver algo más. Por ejemplo: ¿cómo migra los datos de la cuenta del usuario si su identidad cambia de "[email protected]" a "[email protected]"?
  • Por lo general, debe escribir el código para cada proveedor. por ejemplo, Google, Facebook, Twitter.
  • Usted o sus usuarios pueden tener problemas de privacidad. Los proveedores saben cuáles de sus usuarios usan su servicio.
  • Estás confiando en el proveedor. Es posible que un proveedor emita tokens que son válidos para un usuario para otra persona. Esto podría ser para fines legales o no.

Diverso

  • Tanto los ID de sesión como los JWT pueden ser copiados y utilizados por múltiples usuarios. Puede almacenar la dirección IP del cliente en un JWT y validarla, pero eso evita que los clientes se muevan desde Wi-Fi a celular.
Chad Clark
fuente
Para agregar a su respuesta, oAuth puede no ser útil cuando el usuario desea registrarse usando las cuentas de su compañía que generalmente no están asociadas o vinculadas con ninguno de los sitios web de redes sociales o google.
Aftab Naveed
55
No sé por qué esta es la respuesta aceptada? no responde la pregunta real, solo reforma la pregunta de otra manera
amd
1
Usted dice: "Los datos almacenados en la JWT es legible por el cliente Esto puede ser un problema .. ¿Por qué no usar JWE si eso es un problema.?
Plata
Esta respuesta confunde manzanas y naranjas. No debe compararlos con OAuth 2.0 (la especificación de "autorización"). Lo que OP necesita saber es: "Flujo de contraseña del propietario del recurso", que es la autenticación como una concesión.
Onur Yıldırım
5

Pregúntese por qué necesita invalidar el token original.

Un usuario inicia sesión, se genera un token y se apaga la aplicación.

El usuario presiona cerrar sesión, se genera un nuevo token y reemplaza el token original. Una vez más, todo está bien.

Parece que te preocupa el caso en el que ambas fichas cuelgan. ¿Qué pasa si el usuario cierra sesión y luego de alguna manera realiza una solicitud utilizando el token conectado? ¿Cuán realista es este escenario? ¿Es solo un problema durante el cierre de sesión o hay muchos escenarios posibles donde múltiples tokens pueden ser un problema?

Yo mismo no creo que valga la pena preocuparse. Si alguien está interceptando y decodificando sus datos https encriptados, entonces tiene problemas mucho mayores.

Puedes darte una protección adicional poniendo un tiempo de vencimiento en el token original. Entonces, si termina siendo robado o algo así, solo sería bueno por un corto período de tiempo.

De lo contrario, creo que necesitaría tener información de estado en el servidor. No ponga en la lista negra los tokens, sino que incluya en la lista blanca la firma del token actual.

Cerad
fuente
2
Si supone que algunos de sus clientes son maliciosos, es fácil ver que una sesión se copiará y reutilizará, y debe contrarrestar esto en el servidor.
Michael Shaw
1
Mala idea, esto puede ser usado más tarde por hacker, o simplemente bruta forzado ...
CROSP
2
Imagine que un usuario quiere cerrar sesión en todos los demás dispositivos, no es posible usar JWT.
amd
@amd no es posible? ¿Qué sucede si agrego nonce = (aleatorio) y si el usuario cierra sesión, reemplace nonce. Parece simple y efectivo.
Simon B.
3

Puede manejar los problemas de JWT que mencionó almacenando un valor de sal junto con el usuario y utilizando la sal como parte del token para el usuario. Luego, cuando necesite invalidar el token, simplemente cambie la sal.

Sé que han pasado un par de años, pero ahora lo haría de manera diferente. Creo que me aseguraría de que los tokens de acceso tuvieran una vida relativamente corta, digamos una hora. También me aseguraría de usar tokens de actualización con estado en el servidor y luego, cuando quisiera finalizar la sesión de alguien, revocaría el token de actualización eliminándolo del servidor. Luego, después de una hora, el usuario cerrará sesión y tendrá que iniciar sesión nuevamente para recuperar el acceso.

RibaldEddie
fuente
44
Pero nuevamente, en este caso, se llena de estado, por lo que cuál es la razón para crear sal o usar cualquier otro enfoque, puede simplemente almacenar el token en la tabla y eliminarlo cuando deba invalidarse
CROSP
2
También puede invalidar en función del tiempo.
RibaldEddie
¿Cuál es la diferencia entre el tiempo de vencimiento en este caso? ¿Cómo puedo invalidar el token en función del tiempo cuando el usuario desea cerrar sesión desde el cliente móvil? Parece que no hay forma de que API sea apátrida en este caso. ¿Cuál es la solución más adecuada y segura que?
CROSP
2
Lo más adecuado para cerrar sesión desde un solo dispositivo es asegurarse de utilizar un ID de cliente además de la sal. Le sugiero que mire la especificación de token de portador Oauth-jwt para obtener información.
RibaldEddie
Gracias por la respuesta, pero no entiendo por qué debería usar OAuth en este caso.
CROSP