¿Por qué hay un flujo de "Código de autorización" en OAuth2 cuando el flujo "implícito" funciona tan bien?

264

Con el flujo "implícito", el cliente (probablemente un navegador) obtendrá un token de acceso, después de que el propietario del recurso (es decir, el usuario) haya dado acceso.

Sin embargo, con el flujo del "Código de autorización", el cliente (generalmente un servidor web) solo obtiene un código de autorización después de que el Propietario del recurso (es decir, el usuario) haya dado acceso. Con ese código de autorización, el cliente realiza otra llamada a la API pasando client_id y client_secret junto con el código de autorización para obtener el token de acceso. Todo bien descrito aquí .

Ambos flujos tienen exactamente el mismo resultado: un token de acceso. Sin embargo, el flujo "implícito" es mucho más simple.

La pregunta: ¿Por qué molestarse con el flujo del "Código de autorización", cuando el flujo "implícito" parece estar bien? ¿Por qué no usar también "implícito" para el servidor web?

Es más trabajo tanto para el proveedor como para el cliente.

Aron Woost
fuente
44
Echa un vistazo a stackoverflow.com/questions/7522831/…
Jon Nylander
1
Gracias, léelo ya. Sin embargo, no responde la pregunta.
Aron Woost
1
Buena pregunta en realidad y rara vez contestada :) Ver abajo.
Nicolas Garnier
1
@AronWoost Creo que malinterpretas la aplicación web del servidor y la aplicación del navegador
onmyway133
@entropía Esa fue mi pregunta; ¿Por qué no usar el flujo del navegador también para el servidor?
Aron Woost

Respuestas:

293

tl; dr: Todo esto se debe a razones de seguridad.

OAuth 2.0 quería cumplir estos dos criterios:

  1. Desea permitir que los desarrolladores utilicen URI de redireccionamiento no HTTPS porque no todos los desarrolladores tienen un servidor habilitado para SSL y, si lo hacen, no siempre está configurado correctamente (certificados SSL confiables, no autofirmados, reloj de servidor sincronizado ...).
  2. No desea que los piratas informáticos puedan robar tokens de acceso / actualización interceptando solicitudes.

Detalles abajo:

El flujo implícito solo es posible en un entorno de navegador por razones de seguridad:

En el flujo implícito, el token de acceso se pasa directamente como un fragmento hash (no como un parámetro de URL). Una cosa importante sobre el fragmento hash es que, una vez que sigue un enlace que contiene un fragmento hash, solo el navegador es consciente del fragmento hash. Los navegadores pasarán el fragmento hash directamente a la página web de destino (el URI de redireccionamiento / la página web del cliente). El fragmento de hash tiene las siguientes propiedades:

  • No son parte de la solicitud HTTP, por lo tanto, no pueden ser leídos por los servidores y por eso no pueden ser interceptados por servidores / enrutadores intermedios (esto es importante).
  • Solo existen en el navegador, en el lado del cliente, por lo que la única forma de leer el fragmento hash es usar JavaScript que se ejecuta en la página.

Esto hace posible pasar un token de acceso directamente al cliente sin el riesgo de que sea interceptado por un servidor intermediario. Esto tiene la advertencia de que solo es posible en el lado del cliente y necesita que JavaScript se ejecute en el lado del cliente para usar el token de acceso.

El flujo implícito también tiene problemas de seguridad que requieren más lógica para solucionar / evitar, por ejemplo:

  • Un atacante podría obtener un token de acceso de un usuario en un sitio web / aplicación diferente (digamos si es el propietario del otro sitio web / aplicación), registrar el token en su sitio web y luego pasarlo como un parámetro de URL en su sitio web por lo tanto, suplantando al usuario en su sitio web. Para evitar esto, debe verificar el ID de cliente asociado con el token de acceso (por ejemplo, para Google, puede usar el punto final de tokeninfo) para asegurarse de que el token haya sido emitido con su propio ID de cliente (es decir, mediante su propia aplicación) o verificar la firma si está utilizando un IDToken (pero eso requiere su secreto de cliente).
  • Si la solicitud de autenticación no se originó en su propia propiedad (llamada ataques de fijación de sesión), para evitar esto, querrá generar un hash aleatorio desde su sitio web, guárdelo en una cookie y pase el mismo hash en el parámetro de URL de estado de la solicitud de autenticación, cuando el usuario regresa, verifica el parámetro de estado con la cookie y debe coincidir.

En el flujo del código de autorización, no es posible pasar un token de acceso directamente en un parámetro de URL porque los parámetros de URL son parte de la solicitud HTTP, por lo tanto, cualquier servidor / enrutador intermediario por el que pasaría su solicitud (podría ser cientos) podría lea el token de acceso si no está utilizando una conexión cifrada (HTTPS) que permite lo que se conoce como ataques Man-in-the-middle.

En teoría, pasar el token de acceso directamente en un parámetro de URL podría ser posible, pero el servidor de autenticación debería asegurarse de que el URI de redireccionamiento use HTTPS con cifrado TLS y un certificado SSL 'confiable' (generalmente de una Autoridad de Certificación que no es gratuita) para asegurarse de que el servidor de destino es legítimo y que la solicitud HTTP está completamente encriptada. Hacer que todos los desarrolladores compren un certificado SSL y configuren SSL correctamente en su dominio sería un gran problema y reduciría enormemente la adopción. Esta es la razón por la cual se proporciona un "código de autorización" de un solo uso intermediario que solo el receptor legítimo podrá intercambiar (porque necesita el secreto del cliente) y que el código será inútil para los posibles piratas informáticos que interceptan las solicitudes sobre transacciones no cifradas (porque no lo hacen

También podría argumentar que el flujo implícito es menos seguro, hay posibles vectores de ataque como falsificar el dominio al redirigirlo, por ejemplo, secuestrando la dirección IP del sitio web del cliente. Esta es una de las razones por las que el flujo implícito solo otorga tokens de acceso (que se supone que tienen un uso de tiempo limitado) y nunca actualiza los tokens (que son ilimitados en el tiempo). Para solucionar este problema, le aconsejo que aloje sus páginas web en un servidor habilitado para HTTPS siempre que sea posible.

Nicolas Garnier
fuente
12
@AndyDufresne Estas dos solicitudes deben realizarse a través de HTTPS (obligatorio) ya que son solicitudes al servidor OAuth que solo debe admitir HTTPS. Solo el cliente / servidor solicitante no tiene que admitir HTTPS, por lo que solo Auth Codese envía en claro a través de HTTP. Pero Auth Codees inútil sin el ID / secreto del cliente. Básicamente, el punto del flujo del Código OAuth es que la carga de tener un servidor habilitado para SSL recae en el Proveedor OAuth (Google / Facebook, etc.) y no en los usuarios de las API (usted, yo).
Nicolas Garnier
55
Ok, ahora sigo que el código de autenticación se puede pasar por HTTP simple y tiene el riesgo de ser rastreado. Al convertirlo en un código de uso único y aceptar el secreto del cliente para intercambiarlo por un token de acceso, el servidor de autorización podría evitar el ataque Man-in-the-middle. Pero, ¿no se aplica esto también al token de acceso? Dado que el usuario de las API podría estar en HTTP simple, ¿no habrá riesgo de que el pirata informático detecte el token de acceso? PD: agradezco sus esfuerzos para explicar el concepto, incluso después de que haya pasado un tiempo desde que este hilo estuvo activo. Gracias !
Andy Dufresne
8
no pb :) Las solicitudes a la API, que es cuando el token de acceso se envía por cable (para autorizar la solicitud), también se realizan a través de HTTPS obligatoriamente. En teoría, el cliente nunca debería enviar el token de acceso por cable en HTTP simple en ningún momento.
Nicolas Garnier
55
El token de acceso en este paso es parte de la respuesta de la solicitud HTTPS del cliente al servidor de recursos. Esta respuesta todavía está encriptada.
Nicolas Garnier
13
Básicamente, las solicitudes que se inician desde el cliente al servidor de recursos se realizan a través de HTTPS (porque el servidor propietario del recurso debe ser compatible con HTTPS). Solo las solicitudes que se inician desde otro lugar al cliente pueden realizarse a través de HTTP (porque el servidor del cliente podría no ser compatible con HTTPS). Por ejemplo, la redirección que ocurre durante el flujo de autenticación después de que el usuario concede autorización en la página de Gant es una redirección iniciada desde el navegador al servidor del cliente y puede realizarse en HTTP.
Nicolas Garnier
8

El flujo implícito hace que todo el flujo sea bastante fácil, pero también menos seguro .
Como la aplicación cliente, que normalmente es JavaScript que se ejecuta dentro de un navegador, es menos confiable, no se devuelven tokens de actualización para acceso de larga duración.
Debe usar este flujo para aplicaciones que necesitan acceso temporal (unas pocas horas) a los datos del usuario.
Devolver un token de acceso a clientes JavaScript también significa que su aplicación basada en navegador debe tener especial cuidado; piense en los ataques XSS que podrían filtrar el token de acceso a otros sistemas.

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-as-the-client-side-flow

Lakesare
fuente
Esperaría que cuando uno tiene una vulnerabilidad XSS, incluso el flujo del código de autorización no ayuda mucho. Pero estoy de acuerdo en que, dado que la forma en que se pasa el token de acceso a JavaScript en el flujo implícito está estandarizada (como un fragmento hash), y si hay vulnerabilidad XSS en el sitio web, entonces se construye un ataque que lee el token de acceso desde el hash URL El fragmento es bastante fácil. Con el flujo del código de autorización, por otro lado, la falsificación de solicitudes entre sitios podría ser posible.
Marcel
Además, no se trata solo de secuencias de comandos entre sitios. Cualquier biblioteca de JavaScript que se ejecute en su sitio web podría intentar robar el token de acceso (por ejemplo, bibliotecas CDN de terceros o bibliotecas de código abierto que utiliza su marco de JavaScript).
Marcel
2
XSS no es un gran problema ahora cuando tenemos encabezados de Política de Seguridad de Contenido y hashes de Integridad de Sub Recursos (SRI).
Sergey Ponomarev
4

De la especificación OAuth :

4.2. Subvención implícita

El tipo de concesión implícita se utiliza para obtener tokens de acceso (no admite la emisión de tokens de actualización) y está optimizado para clientes públicos que se sabe que operan un URI de redireccionamiento particular. Estos clientes generalmente se implementan en un navegador utilizando un lenguaje de script como JavaScript.

Dado que este es un flujo basado en la redirección, el cliente debe ser capaz de interactuar con el agente de usuario del propietario del recurso (generalmente un navegador web) y capaz de recibir las solicitudes entrantes (a través de la redirección) desde el servidor de autorización.

A diferencia del tipo de concesión de código de autorización, en el que el cliente realiza solicitudes de autorización y un token de acceso por separado, el cliente recibe el token de acceso como resultado de la solicitud de autorización.

El tipo de concesión implícita no incluye la autenticación del cliente y se basa en la presencia del propietario del recurso y el registro del URI de redireccionamiento. Debido a que el token de acceso está codificado en el URI de redireccionamiento, puede estar expuesto al propietario del recurso y a otras aplicaciones que residen en el mismo dispositivo.

Entonces, qué podemos considerar:

  1. Esto es para OAuth público, es decir, cuando el cliente no necesita estar registrado y no tiene sus propios secretos de cliente. Pero, ¿qué servidor de autenticación comprueba la URL de redireccionamiento y esto es realmente suficiente para la seguridad?

  2. El token de acceso se encuentra en la barra de direcciones del navegador para que el usuario pueda copiar la url y enviarla a otra persona y también se registra como el usuario, es decir, es algo así como la fijación de la sesión. Pero el navegador realiza una redirección adicional con el reemplazo del historial para eliminar el fragmento hash de la url. También es posible que un pirata informático robe el token de acceso olfateando un tráfico HTTP, pero HTTPS puede protegerlo fácilmente. Algunas extensiones de navegador maliciosas pueden tener acceso a las URL desde la barra de direcciones, pero en última instancia, esta es una mala situación, como un certificado HTTPS roto. E incluso el flujo de código Auth no puede ayudar aquí, ether. Entonces, lo que puedo ver es que pasar el token de acceso a través del fragmento hash de url es absolutamente seguro.

  3. La separación del token de acceso efímero y el token de actualización son inútiles cuando se usa un HTTPS y, para ser sincero, no es tan útil incluso en HTTP sin formato. Pero el hecho de que el cliente a través del flujo implícito no pueda recibir el token de actualización tampoco tiene sentido.

Por lo tanto, creo que deberíamos introducir un nuevo flujo de concesión "implícito seguro" que funcione estrictamente sobre https, permita el token de actualización (o deberíamos deshacernos de ellos), y es preferible que el flujo de concesión Auth Cose

stokito
fuente
3

Para nosotros, nuestros clientes querían poder autenticarse con nuestra aplicación en sus teléfonos una vez, y no tener que volver a iniciar sesión durante semanas. Con el flujo de código, obtienes un token de actualización junto con tu token de acceso. El flujo implícito no le proporciona un token de actualización. El token de acceso tiene una caducidad relativamente corta, pero los tokens de actualización pueden tener una caducidad de hasta 90 días. Cada vez que el token de acceso caduca, el código del cliente y del servidor puede usar ese token de actualización para obtener un nuevo token de acceso más un token de actualización, todo detrás de escena, sin intervención alguna del usuario. Un token de actualización solo se puede usar una vez. No puede hacer esto con Flujo implícito. Si usa Flujo implícito y su usuario no interactúa con su aplicación durante más de una hora, tendrá que iniciar sesión nuevamente cuando regrese. Eso no era aceptable en nuestro caso de uso,

Esto funciona y es seguro porque los tokens de actualización se pueden revocar. Si un cliente dice que perdió su teléfono o su computadora portátil o que un hacker ingresó a su escritorio, simplemente podemos revocar todos los tokens de actualización para ese usuario. Durante todo el proceso, ninguna información de identificación personal (PII) toca nuestro código, es decir, la contraseña del usuario.

El flujo de código es increíble, pero requiere más trabajo. MS no tiene una biblioteca angular para manejarlo actualmente, así que tuve que escribir una. Si está interesado, puedo ayudarlo.

Tim Hardy
fuente
2

Mi respuesta es: no puede implementar el flujo implícito de una manera segura y simple con el servidor de aplicaciones web.

El proceso de autorización de la aplicación web implica la interacción del usuario, por lo que Authentication Server debe redirigir el navegador del usuario a la página de destino de la aplicación web después de la autenticación y el consentimiento del usuario (no veo ninguna otra forma de devolver al usuario a la aplicación web después de alguna interacción con Servidor de autenticación).

Entonces, el token debe pasarse a la aplicación web usando la URL de redireccionamiento, ¿verdad?

Como @NicolasGarnier explicó en su respuesta y comentarios, no hay forma de pasar el token como un fragmento de URL: no llegará al servidor de aplicaciones web.

Y pasar el token como un parámetro de URL de la URL de redireccionamiento sería inseguro incluso bajo HTTPS: si la página de destino (que sea "página de saludo") contiene recursos (imágenes, scripts, etc.) estos recursos serán obtenidos por el navegador a través de la serie de solicitudes HTTP (S) (cada una de las cuales tiene un Refererencabezado HTTP que contiene la URL exacta de la "página de saludo", incluidos los parámetros de URL). Esta es la forma en que el token puede filtrarse.

Parece que no hay forma de pasar el token en la URL de redireccionamiento. Es por eso que necesita una segunda llamada (ya sea del Servidor de autenticación al Cliente (¿pero a qué URL?) O del Cliente al Servidor de autenticación (la segunda llamada en el flujo del Código de autorización))

Lu55
fuente