0Auth
OAuth 2.0 authentication vulnerabilities
Last updated
OAuth 2.0 authentication vulnerabilities
Last updated
Mientras navegas por la web, es casi seguro que te has encontrado con sitios que te permiten iniciar sesión con tu cuenta de redes sociales. Lo más probable es que esta función esté diseñada con el popular marco OAuth 2.0. OAuth 2.0 es muy interesante para los atacantes porque es extremadamente común y, por naturaleza, propenso a errores de implementación. Esto puede generar una serie de vulnerabilidades, lo que permite a los atacantes obtener datos confidenciales de los usuarios y, potencialmente, eludir la autenticación por completo.
En esta sección, le enseñaremos a identificar y explotar algunas de las los mecanismos de autenticación de OAuth 2.0. No se preocupe si no está muy familiarizado con la autenticación de OAuth: le proporcionamos mucha información de fondo para ayudarlo a comprender los conceptos clave que necesitará. También exploraremos algunas . Por último, incluimos algunas pautas sobre cómo contra este tipo de ataques.
OAuth es un marco de autorización de uso común que permite a los sitios web y las aplicaciones web solicitar acceso limitado a la cuenta de un usuario en otra aplicación. Fundamentalmente, OAuth permite al usuario otorgar este acceso sin exponer sus credenciales de inicio de sesión a la aplicación solicitante. Esto significa que los usuarios pueden definir con precisión qué datos desean compartir en lugar de tener que entregar el control total de su cuenta a un tercero.
El proceso básico de OAuth se utiliza ampliamente para integrar funciones de terceros que requieren acceso a determinados datos de la cuenta de un usuario. Por ejemplo, una aplicación puede utilizar OAuth para solicitar acceso a su lista de contactos de correo electrónico para poder sugerir personas con las que conectarse. Sin embargo, el mismo mecanismo también se utiliza para proporcionar servicios de autenticación de terceros, lo que permite a los usuarios iniciar sesión con una cuenta que tienen en un sitio web diferente.
Aunque OAuth 2.0 es el estándar actual, algunos sitios web aún utilizan la versión 1a anterior. OAuth 2.0 se escribió desde cero en lugar de desarrollarse directamente a partir de OAuth 1.0. Como resultado, ambos son muy diferentes. Tenga en cuenta que el término "OAuth" se refiere exclusivamente a OAuth 2.0 en este material.
El tipo de concesión de OAuth determina la secuencia exacta de pasos que intervienen en el proceso de OAuth. El tipo de concesión también afecta la forma en que la aplicación cliente se comunica con el servicio de OAuth en cada etapa, incluida la forma en que se envía el token de acceso. Por este motivo, los tipos de concesión suelen denominarse "flujos de OAuth".
Un servicio OAuth debe configurarse para admitir un tipo de concesión en particular antes de que una aplicación cliente pueda iniciar el flujo correspondiente. La aplicación cliente especifica qué tipo de concesión desea utilizar en la solicitud de autorización inicial que envía al servicio OAuth.
Para este caso nos centraremos en los dos tipos de concesión o “Flujo de Oauth” → Authorization
e Implicit
que son los más comunes.
Para cualquier tipo de concesión de OAuth, la aplicación cliente debe especificar a qué datos desea acceder y qué tipo de operaciones desea realizar. Para ello, utiliza el scope
parámetro de la solicitud de autorización que envía al servicio OAuth.
En el caso de OAuth básico, los ámbitos para los que una aplicación cliente puede solicitar acceso son exclusivos de cada servicio OAuth. Como el nombre del ámbito es simplemente una cadena de texto arbitraria, el formato puede variar drásticamente entre proveedores. Algunos incluso utilizan una URI completa como nombre del ámbito, de forma similar a un punto final de API REST. Por ejemplo, al solicitar acceso de lectura a la lista de contactos de un usuario, el nombre del ámbito puede adoptar cualquiera de las siguientes formas según el servicio OAuth que se utilice:
Authorization
:El tipo de concesión del código de autorización inicialmente parece bastante complicado, pero en realidad es más simple de lo que piensa una vez que está familiarizado con algunos conceptos básicos.
En resumen, la aplicación cliente y el servicio OAuth primero utilizan redirecciones para intercambiar una serie de solicitudes HTTP basadas en el navegador que inician el flujo. Se le pregunta al usuario si acepta el acceso solicitado. Si acepta, se le otorga a la aplicación cliente un "código de autorización". Luego, la aplicación cliente intercambia este código con el servicio OAuth para recibir un "token de acceso", que puede usar para realizar llamadas API para obtener los datos de usuario relevantes.
Toda la comunicación que se produce desde el intercambio de código/token en adelante se envía de servidor a servidor a través de un canal de retorno seguro y preconfigurado y, por lo tanto, es invisible para el usuario final. Este canal seguro se establece cuando la aplicación cliente se registra por primera vez en el servicio OAuth. En ese momento, client_secret
también se genera un correo electrónico que la aplicación cliente debe utilizar para autenticarse al enviar estas solicitudes de servidor a servidor.
Como los datos más confidenciales (el token de acceso y los datos del usuario) no se envían a través del navegador, este tipo de concesión es posiblemente el más seguro. Lo ideal es que las aplicaciones del lado del servidor siempre utilicen este tipo de concesión si es posible.
La aplicación cliente envía una solicitud al punto final del servicio OAuth /authorization
solicitando permiso para acceder a datos específicos del usuario. Tenga en cuenta que la asignación del punto final puede variar entre proveedores: nuestros laboratorios utilizan el punto final /auth
para este propósito. Sin embargo, siempre debería poder identificar el punto final en función de los parámetros utilizados en la solicitud.
Esta solicitud contiene los siguientes parámetros importantes, generalmente proporcionados en la cadena de consulta:
client_id
Parámetro obligatorio que contiene el identificador único de la aplicación cliente. Este valor se genera cuando la aplicación cliente se registra en el servicio OAuth.
redirect_uri
La URI a la que se debe redirigir el navegador del usuario al enviar el código de autorización a la aplicación cliente. También se conoce como "URI de devolución de llamada" o "punto final de devolución de llamada". Muchos ataques OAuth se basan en explotar fallas en la validación de este parámetro.
response_type
Determina qué tipo de respuesta espera la aplicación cliente y, por lo tanto, qué flujo desea iniciar. Para el tipo de concesión de código de autorización, el valor debe ser code
.
scope
state
Cuando el servidor de autorización recibe la solicitud inicial, redirigirá al usuario a una página de inicio de sesión, donde se le solicitará que inicie sesión en su cuenta con el proveedor de OAuth. Por ejemplo, esta suele ser su cuenta de redes sociales.
A continuación, se les presentará una lista de datos a los que la aplicación cliente desea acceder, en función de los alcances definidos en la solicitud de autorización. El usuario puede elegir si desea o no dar su consentimiento para este acceso.
Es importante tener en cuenta que una vez que el usuario haya aprobado un alcance determinado para una aplicación cliente, este paso se completará automáticamente siempre que el usuario aún tenga una sesión válida con el servicio OAuth. En otras palabras, la primera vez que el usuario seleccione "Iniciar sesión con redes sociales", deberá iniciar sesión manualmente y dar su consentimiento, pero si vuelve a visitar la aplicación cliente más tarde, a menudo podrá volver a iniciar sesión con un solo clic.
Si el usuario consiente el acceso solicitado, su navegador será redirigido al /callback
punto final que se especificó en el redirect_uri
parámetro de la solicitud de autorización. La GET
solicitud resultante contendrá el código de autorización como parámetro de consulta. Dependiendo de la configuración, también podrá enviar el state
parámetro con el mismo valor que en la solicitud de autorización.
Una vez que la aplicación cliente recibe el código de autorización, debe intercambiarlo por un token de acceso. Para ello, envía una POST
solicitud de servidor a servidor al punto final del servicio OAuth /token
. Toda la comunicación a partir de este momento se lleva a cabo en un canal de retorno seguro y, por lo tanto, normalmente no puede ser observada ni controlada por un atacante.
Además de la client_id
autorización y code
, notarás los siguientes parámetros nuevos:
client_secret
La aplicación cliente debe autenticarse incluyendo la clave secreta que se le asignó al registrarse en el servicio OAuth.
grant_type
Se utiliza para garantizar que el nuevo punto final sepa qué tipo de concesión desea utilizar la aplicación cliente. En este caso, debe configurarse en authorization_code
.
El servicio OAuth validará la solicitud de token de acceso. Si todo es como se espera, el servidor responde otorgando a la aplicación cliente un token de acceso con el alcance solicitado.
Ahora que la aplicación cliente tiene el código de acceso, puede finalmente obtener los datos del usuario del servidor de recursos. Para ello, realiza una llamada API al /userinfo
punto final del servicio OAuth. El token de acceso se envía en el Authorization: Bearer
encabezado para demostrar que la aplicación cliente tiene permiso para acceder a estos datos.
El servidor de recursos debe verificar que el token sea válido y que pertenezca a la aplicación cliente actual. De ser así, responderá enviando el recurso solicitado, es decir, los datos del usuario en función del alcance del token de acceso.
La aplicación cliente puede finalmente utilizar estos datos para el propósito previsto. En el caso de la autenticación OAuth, normalmente se utilizarán como ID para otorgarle al usuario una sesión autenticada, lo que le permitirá iniciar sesión de manera efectiva.
Implicit
:El tipo de concesión implícita es mucho más simple. En lugar de obtener primero un código de autorización y luego intercambiarlo por un token de acceso, la aplicación cliente recibe el token de acceso inmediatamente después de que el usuario da su consentimiento.
Quizás te preguntes por qué las aplicaciones cliente no siempre utilizan el tipo de concesión implícita. La respuesta es relativamente sencilla: es mucho menos seguro. Cuando se utiliza el tipo de concesión implícita, toda la comunicación se realiza a través de redirecciones del navegador; no hay un canal de retorno seguro como en el flujo del código de autorización. Esto significa que el token de acceso confidencial y los datos del usuario están más expuestos a posibles ataques.
El tipo de concesión implícita es más adecuado para aplicaciones de página única y aplicaciones de escritorio nativas, que no pueden almacenar fácilmente client_secret
en el back-end y, por lo tanto, no se benefician tanto del uso del tipo de concesión de código de autorización.
El flujo implícito comienza de forma muy similar al flujo del código de autorización. La única diferencia importante es que el response_type
parámetro debe configurarse en token
.
El usuario inicia sesión y decide si acepta o no los permisos solicitados. Este proceso es exactamente el mismo que el del flujo del código de autorización.
Si el usuario da su consentimiento para el acceso solicitado, las cosas empiezan a cambiar. El servicio OAuth redirigirá el navegador del usuario a la dirección redirect_uri
especificada en la solicitud de autorización. Sin embargo, en lugar de enviar un parámetro de consulta que contenga un código de autorización, enviará el token de acceso y otros datos específicos del token como un fragmento de URL.
Como el token de acceso se envía en un fragmento de URL, nunca se envía directamente a la aplicación cliente. En su lugar, la aplicación cliente debe utilizar un script adecuado para extraer el fragmento y almacenarlo.
Una vez que la aplicación cliente ha extraído correctamente el token de acceso del fragmento de URL, puede usarlo para realizar llamadas API al /userinfo
punto final del servicio OAuth. A diferencia del flujo de código de autorización, esto también sucede a través del navegador.
El servidor de recursos debe verificar que el token sea válido y que pertenezca a la aplicación cliente actual. De ser así, responderá enviando el recurso solicitado, es decir, los datos del usuario en función del alcance asociado al token de acceso.
La aplicación cliente puede finalmente utilizar estos datos para el propósito previsto. En el caso de la autenticación OAuth, normalmente se utilizarán como ID para otorgarle al usuario una sesión autenticada, lo que le permitirá iniciar sesión de manera efectiva.
Aunque en un principio no estaba pensado para este fin, OAuth ha evolucionado hasta convertirse también en un medio para autenticar a los usuarios. Por ejemplo, probablemente conozca la opción que ofrecen muchos sitios web para iniciar sesión con su cuenta de redes sociales existente en lugar de tener que registrarse en el sitio web en cuestión. Siempre que vea esta opción, es muy probable que esté basada en OAuth 2.0.
En el caso de los mecanismos de autenticación OAuth, los flujos básicos de OAuth siguen siendo en gran medida los mismos; la principal diferencia es cómo la aplicación cliente utiliza los datos que recibe. Desde la perspectiva del usuario final, el resultado de la autenticación OAuth es algo que se parece mucho al inicio de sesión único (SSO) basado en SAML. En estos materiales, nos centraremos exclusivamente en las vulnerabilidades de este caso de uso similar al SSO.
La autenticación OAuth generalmente se implementa de la siguiente manera:
El usuario elige la opción de iniciar sesión con su cuenta de redes sociales. A continuación, la aplicación cliente utiliza el servicio OAuth del sitio de redes sociales para solicitar acceso a algunos datos que puede utilizar para identificar al usuario. Esta podría ser, por ejemplo, la dirección de correo electrónico registrada en su cuenta.
Después de recibir un token de acceso, la aplicación cliente solicita estos datos al servidor de recursos, generalmente desde un /userinfo
punto final dedicado.
Una vez que recibe los datos, la aplicación cliente los utiliza en lugar de un nombre de usuario para iniciar la sesión del usuario. El token de acceso que recibió del servidor de autorización a menudo se utiliza en lugar de una contraseña tradicional.
Vamos a ver esto en más detalle con un simple laboratorio (el primero), para entender de que se trata:
Puede ver un ejemplo simple de cómo se ve esto en el siguiente laboratorio. Simplemente complete la opción "Iniciar sesión con redes sociales" mientras envía tráfico a través de Burp y luego estudie la serie de interacciones de OAuth en el historial del proxy. Puede iniciar sesión con las credenciales
wiener:peter
. Tenga en cuenta que esta implementación es deliberadamente vulnerable; le enseñaremos cómo aprovechar esto más adelante.
Sin embargo, cuando se utiliza OAuth para la autenticación, se suelen utilizar los ámbitos estandarizados de OpenID Connect. Por ejemplo, el ámbito openid profile otorgará a la aplicación cliente acceso de lectura a un conjunto predefinido de información básica sobre el usuario, como su dirección de correo electrónico, nombre de usuario, etc. Hablaremos más sobre más adelante.
Se utiliza para especificar a qué subconjunto de los datos del usuario desea acceder la aplicación cliente. Tenga en cuenta que estos pueden ser ámbitos personalizados establecidos por el proveedor de OAuth o ámbitos estandarizados definidos por la especificación de OpenID Connect. Trataremos con más detalle más adelante.
Almacena un valor único e indescifrable que está vinculado a la sesión actual en la aplicación cliente. El servicio OAuth debe devolver este valor exacto en la respuesta, junto con el código de autorización. Este parámetro funciona como una forma de token para la aplicación cliente, ya que garantiza que la solicitud a su /callback
punto final provenga de la misma persona que inició el flujo OAuth.