Seguridad móvil OAuth 2.0



Hola a todos! Soy Nikita Stupin, especialista en seguridad de la información, Mail.Ru Mail. No hace mucho tiempo, realicé una investigación de vulnerabilidad en dispositivos móviles OAuth 2.0. Para crear un esquema móvil seguro de OAuth 2.0, no es suficiente implementar el estándar en su forma pura y verificar redirect_uri. Es necesario tener en cuenta los detalles de las aplicaciones móviles y aplicar mecanismos de protección adicionales.

En este artículo, quiero compartir con ustedes conocimientos sobre ataques en dispositivos móviles OAuth 2.0, sobre métodos de protección y la implementación segura de este protocolo. Todos los componentes de protección necesarios, que analizaré a continuación, se implementan en el último SDK para los clientes móviles Mail.Ru Mail.

La naturaleza y la función de OAuth 2.0


OAuth 2.0 es un protocolo de autorización que describe cómo es seguro para un servicio de cliente acceder a los recursos del usuario en un proveedor de servicios. Al mismo tiempo, OAuth 2.0 evita que el usuario tenga que ingresar una contraseña fuera del proveedor de servicios: todo el proceso se reduce a hacer clic en el botón "Acepto otorgar acceso a ...".

Un proveedor en términos de OAuth 2.0 es un servicio que posee los datos del usuario y, con el permiso del usuario, proporciona servicios de terceros (clientes) con acceso seguro a estos datos. Un cliente es una aplicación que desea recibir datos de usuario de un proveedor.

Algún tiempo después del lanzamiento del protocolo OAuth 2.0, los desarrolladores comunes lo adaptaron para la autenticación, aunque originalmente no estaba destinado a esto. La autenticación cambia el vector de ataque de los datos del usuario que se almacenan en el proveedor de servicios a las cuentas de usuario del servicio del usuario.

No se limitó solo a la autenticación. En la era de las aplicaciones móviles y la exaltación de la conversión, ingresar a la aplicación con un solo botón se ha vuelto muy tentador. Los desarrolladores pusieron OAuth 2.0 en rieles móviles. Naturalmente, pocas personas pensaban en la seguridad y las características específicas de las aplicaciones móviles: una y otra vez, y en producción. Sin embargo, OAuth 2.0 generalmente no funciona bien fuera de las aplicaciones web: se observan los mismos problemas tanto en aplicaciones móviles como de escritorio.

Veamos cómo hacer un OAuth 2.0 móvil seguro.

Como funciona


Recuerde que en los dispositivos móviles, el cliente puede no ser un navegador, sino una aplicación móvil sin backend. Por lo tanto, nos enfrentamos a dos problemas de seguridad principales para OAuth 2.0 móvil:

  1. El cliente no es de confianza.
  2. El comportamiento de una redirección desde un navegador a una aplicación móvil depende de la configuración y las aplicaciones que el usuario haya instalado.

La aplicación móvil es un cliente público.


Para comprender la raíz del primer problema, veamos cómo funciona OAuth 2.0 en caso de interacción de servidor a servidor, y luego compárelo con OAuth 2.0 en caso de interacción de cliente a servidor.

En ambos casos, todo comienza con el hecho de que el cliente del servicio se registra con el proveedor del servicio y recibe client_id y, en algunos casos, client_secret . El valor client_id es público y es necesario para identificar el servicio del cliente, a diferencia de client_secret , cuyo valor es privado. El proceso de registro se describe con más detalle en RFC 7591 .

El siguiente diagrama muestra el funcionamiento de OAuth 2.0 en la comunicación de servidor a servidor.


Imagen tomada de https://tools.ietf.org/html/rfc6749#section-1.2

Hay 3 etapas principales del protocolo OAuth 2.0:

  1. [Pasos de CA] Obtenga el código de autorización (en adelante, simplemente code ).
  2. [Pasos DE] code intercambio para access_token .
  3. Acceda al recurso utilizando access_token .

Examinemos el recibo del código con más detalle:

  1. [Paso A] El cliente del servicio redirige al usuario al proveedor del servicio.
  2. [Paso B] El proveedor de servicios solicita permiso al usuario para proporcionar datos al servicio del cliente (flecha B hacia arriba). El usuario proporciona acceso a los datos (flecha B a la derecha).
  3. [Paso C] El proveedor de servicios devuelve el code al navegador del usuario, que redirige el code servicio del cliente.

Veamos access_token obtener access_token más detalle:

  1. [Paso D] El servidor del cliente envía una solicitud de access_token . La solicitud incluye: code , client_secret y redirect_uri .
  2. [Paso E] En el caso de code válido, client_secret y redirect_uri , client_secret proporciona client_secret .

La solicitud de access_token a access_token se realiza de acuerdo con el esquema de servidor a servidor, por lo tanto, en general, para robar client_secret atacante debe piratear el servidor servidor-cliente o el servidor del proveedor de servicios.

Ahora veamos cómo se ve el esquema OAuth 2.0 en un dispositivo móvil sin backend (interacción de cliente a servidor).


Imagen tomada de https://tools.ietf.org/html/rfc8252#section-4.1

El esquema general se divide en los mismos 3 pasos principales:

  1. [pasos 1-4 en la imagen] Obtenga el code .
  2. [pasos 5-6 en la imagen] code intercambio para access_token .
  3. Acceda al recurso utilizando access_token .

Sin embargo, en este caso, la aplicación móvil también actúa como un servidor, lo que significa que client_secret estará client_secret dentro de la aplicación. Esto lleva al hecho de que en dispositivos móviles es imposible mantener el secreto lient_secret de un atacante. client_secret dos formas de client_secret a la aplicación: filtrar el tráfico de la aplicación al servidor o aplicar ingeniería inversa a la aplicación. Ambos métodos son fáciles de implementar, por lo que client_secret inútil en dispositivos móviles.

Con respecto al esquema de cliente a servidor, es posible que tenga una pregunta: "¿por qué no obtener access_token inmediatamente?". Parecería, ¿por qué necesitamos un paso adicional? Además, hay un esquema de concesión implícita en el que el cliente recibe inmediatamente un access_token . Aunque puede usarse en algunos casos, veremos a continuación que la Subvención implícita no es adecuada para OAuth 2.0 móvil seguro.

Redireccionar en dispositivos móviles


En general, para una redirección desde un navegador a una aplicación en dispositivos móviles, se utilizan el esquema URI personalizado y los mecanismos AppLink . Ninguno de estos mecanismos en su forma pura es tan confiable como una redirección de navegador.

El esquema URI personalizado (o enlace profundo) se utiliza de la siguiente manera: el desarrollador define el esquema de la aplicación antes del ensamblaje. El esquema puede ser arbitrario, mientras que en el mismo dispositivo se pueden instalar varias aplicaciones con el mismo esquema. Todo es bastante simple cuando cada aplicación en el dispositivo corresponde a una aplicación. Pero, ¿qué pasa si dos aplicaciones registraron el mismo circuito en el mismo dispositivo? ¿Cómo puede determinar el sistema operativo cuál de las dos aplicaciones se abrirá al acceder al esquema URI personalizado? Android mostrará una ventana con la elección de la aplicación en la que desea abrir un enlace. En iOS, el comportamiento no está definido , lo que significa que cualquiera de las dos aplicaciones se puede abrir. En ambos casos, un atacante puede interceptar código o access_token .

AppLink, en contraste con el esquema URI personalizado, está garantizado para abrir la aplicación correcta, pero este mecanismo tiene varias desventajas:

  1. Cada cliente de servicio debe pasar independientemente el procedimiento de verificación .
  2. Los usuarios de Android pueden desactivar AppLink para una aplicación específica en la configuración.
  3. Android por debajo de 6.0 e iOS por debajo de 9.0 no son compatibles con AppLink.

Las desventajas anteriores de AppLink, en primer lugar, aumentan el umbral de entrada para posibles servicios de cliente y, en segundo lugar, pueden llevar al hecho de que, en determinadas circunstancias, el usuario no trabajará con OAuth 2.0. Esto hace que AppLink no sea adecuado para reemplazar los redireccionamientos del navegador en el protocolo OAuth 2.0.

¿A qué atacar?


Los problemas de OAuth 2.0 móvil también dieron lugar a ataques específicos. Veamos qué son y cómo funcionan.

Ataque de intercepción del código de autorización


Datos iniciales: una aplicación legítima (cliente OAuth 2.0) y una aplicación maliciosa que registró el mismo esquema que el legítimo se instalan en el dispositivo del usuario. La siguiente figura muestra el esquema de ataque.


Imagen tomada de https://tools.ietf.org/html/rfc7636#section-1

Aquí está el problema: en el paso 4, el navegador devuelve el code a la aplicación a través del Esquema de URI personalizado, por lo que el code puede ser interceptado por el malware (porque registró el mismo esquema que la aplicación legítima). Después de eso, el malware cambia el code a access_token y obtiene acceso a los datos del usuario.

¿Cómo protegerte? En algunos casos, se pueden utilizar mecanismos de comunicación entre procesos; hablaremos de ellos a continuación. En el caso general, debe aplicar un esquema llamado Clave de prueba para el intercambio de código . Su esencia se refleja en el siguiente diagrama.


Imagen tomada de https://tools.ietf.org/html/rfc7636#section-1.1

En las solicitudes del cliente, hay varios parámetros adicionales: code_verifier , code_challenge (en el t(code_verifier) ) y code_challenge_method (en el diagrama t_m ).

Code_verifier es un número aleatorio de al menos 256 bits de longitud que se usa solo una vez . Es decir, para cada solicitud de code cliente debe generar un nuevo code_verifier .

Code_challenge_method es el nombre de una función de conversión, con mayor frecuencia SHA-256.

Code_challenge es un code_verifier al que se ha code_challenge_method y codificado la conversión code_challenge_method en la URL Safe Base64.

La conversión de code_verifier a code_challenge necesaria para proteger contra los vectores de ataque basados ​​en la intercepción de code_verifier (por ejemplo, desde los registros del sistema del dispositivo) cuando se solicita el code .

Si el dispositivo del usuario no admite SHA-256, se permite una degradación hasta que falte la conversión code_verifier . En todos los demás casos, debe usar SHA-256.

El esquema funciona de la siguiente manera:

  1. El cliente genera un code_verifier y lo recuerda.
  2. El cliente selecciona code_challenge_method y obtiene code_challenge de code_verifier .
  3. [Paso A] El cliente solicita el code , con code_challenge y code_challenge_method agregado a la solicitud.
  4. [Paso B] El proveedor recuerda el code_challenge y code_challenge_method en el servidor y devuelve el code cliente.
  5. [Paso C] El cliente solicita access_token , y se agrega access_token a la code_verifier .
  6. El proveedor recibe el code_challenge del code_challenge entrante, y luego lo code_challenge el code_challenge , que recordaba.
  7. [Paso D] Si los valores coinciden, el proveedor emite un access_token cliente.

Veamos por qué code_challenge permite protegerte de un ataque de intercepción de código. Para hacer esto, pasaremos por las etapas de obtener access_token .

  1. Primero, una aplicación legítima solicita el code ( code_challenge y code_challenge_method envían junto con la solicitud ).
  2. El malware intercepta el code (pero no code_challenge , porque no hay code_challenge en la respuesta ).
  3. El malware solicita access_token (con code válido, pero sin code_verifier válido).
  4. El servidor nota la code_challenge coincidencia code_challenge y arroja un error.

Tenga en cuenta que el atacante no tiene la capacidad de adivinar el code_verifier (al azar 256 bits!) O encontrarlo en algún lugar de los registros ( code_verifier se transmite una vez).

Si todo esto se reduce a una frase, code_challenge permite al proveedor de servicios responder la pregunta: " access_token solicita access_token por la misma aplicación cliente que solicitó el code o por otra?"

OAuth 2.0 CSRF


En dispositivos móviles, OAuth 2.0 a menudo se usa como mecanismo de autenticación. Como recordamos, la autenticación a través de OAuth 2.0 difiere de la autorización en que las vulnerabilidades de OAuth 2.0 afectan los datos del usuario del lado del cliente del servicio y no del proveedor del servicio. Como resultado, el ataque CSRF en OAuth 2.0 le permite robar la cuenta de otra persona.

Considere un ataque CSRF contra OAuth 2.0 utilizando el ejemplo de la aplicación cliente de taxi y el proveedor provider.com. Primero, un atacante inicia sesión en attacker@provider.com en su dispositivo y recibe un code para el taxi. Después de eso, el atacante interrumpe el proceso OAuth 2.0 y genera un enlace:

com.taxi.app://oauth?
code=b57b236c9bcd2a61fcd627b69ae2d7a6eb5bc13f2dc25311348ee08df43bc0c4

Luego, el atacante envía un enlace a la víctima, por ejemplo, bajo la apariencia de una carta o SMS de la administración del taxi. La víctima access_token enlace, se abre una aplicación de taxi en su teléfono, que recibe access_token , y como resultado, la víctima termina en la cuenta de taxi del atacante . Sin darse cuenta de la captura, la víctima usa esta cuenta: hace viajes, ingresa sus datos, etc.

Ahora, un atacante puede iniciar sesión en la cuenta de taxi de la víctima en cualquier momento porque está vinculado a attacker@provider.com . El ataque CSRF al iniciar sesión le permitió robar una cuenta.

Los ataques CSRF generalmente están protegidos con un token CSRF (también llamado state ), y OAuth 2.0 no es una excepción. Cómo usar el token CSRF:

  1. La aplicación cliente genera y almacena el token CSRF en el dispositivo móvil del usuario.
  2. La aplicación cliente incluye el token CSRF en la solicitud de code .
  3. El servidor devuelve el mismo token CSRF en la respuesta junto con el código.
  4. La aplicación cliente compara el token CSRF entrante y almacenado. Si los valores coinciden, entonces el proceso continúa.

Requisitos del token CSRF: nonce de al menos 256 bits de largo, obtenido de una buena fuente de secuencias pseudoaleatorias.

En resumen, el token CSRF permite que la aplicación cliente responda la pregunta: "¿Estaba empezando a obtener access_token , o alguien está tratando de engañarme?"

Malware que finge ser un cliente legítimo


Algunos programas maliciosos pueden imitar aplicaciones legítimas y generar una pantalla de consentimiento en su nombre (la pantalla de consentimiento es una pantalla en la que el usuario ve: "Acepto otorgar acceso a ..."). El usuario desatento puede hacer clic en "permitir" y, como resultado, el malware obtiene acceso a los datos del usuario.

Android e iOS proporcionan mecanismos para la verificación mutua de aplicaciones. La aplicación del proveedor puede verificar la legitimidad de la aplicación del cliente y viceversa.

Desafortunadamente, si el mecanismo OAuth 2.0 usa una transmisión a través de un navegador, entonces no puede defenderse contra este ataque.

Otros ataques


Examinamos los ataques que son exclusivos de OAuth 2.0 móvil. Sin embargo, no te olvides de los ataques en OAuth 2.0 regular: redirect_uri , intercepción de tráfico a través de una conexión insegura, etc. Puedes leer más sobre ellos aquí .

Que hacer


Aprendimos cómo funciona el protocolo OAuth 2.0 y descubrimos qué vulnerabilidades existen en las implementaciones de este protocolo en dispositivos móviles. Ahora, creemos un esquema seguro de OAuth 2.0 móvil a partir de piezas individuales.

Bueno, malo OAuth 2.0


Comencemos con cómo elevar correctamente la pantalla de consentimiento. En dispositivos móviles, hay dos formas de abrir una página web desde una aplicación nativa (ejemplos de aplicaciones nativas: Mail.Ru Mail, VK, Facebook).



El primer método se llama la pestaña personalizada del navegador (en la imagen de la izquierda). Nota : La pestaña personalizada del navegador en Android se denomina pestaña personalizada de Chrome y en iOS SafariViewController. De hecho, esta es una pestaña normal del navegador, que se muestra directamente en la aplicación, es decir No hay cambio visual entre aplicaciones.

El segundo método se llama "raise WebView" (en la imagen de la derecha), en relación con OAuth 2.0 móvil, considero que es malo.

WebView es un navegador independiente para una aplicación nativa.

Un " navegador independiente" significa que WebView no permite el acceso a cookies, almacenamiento, caché, historial y otros datos de los navegadores Safari y Chrome. Lo contrario también es cierto: Safari y Chrome no pueden acceder a los datos de WebView.

" Navegador para una aplicación nativa " significa que la aplicación nativa que generó WebView tiene acceso completo a cookies, almacenamiento, caché, historial y otros datos de WebView.

Ahora imagine: el usuario presiona el botón "iniciar sesión usando ..." y el WebView de la aplicación maliciosa le pide su nombre de usuario y contraseña al proveedor de servicios.

Fracaso a la vez en todos los frentes:

  1. El usuario ingresa el nombre de usuario y la contraseña de la cuenta del proveedor de servicios en la aplicación, que puede robar fácilmente estos datos.
  2. OAuth 2.0 se desarrolló originalmente para no ingresar un nombre de usuario y contraseña de un proveedor de servicios.
  3. El usuario se acostumbra a ingresar el nombre de usuario y la contraseña en cualquier lugar, la probabilidad de phishing aumenta.

Dado que todos los argumentos están en contra de WebView, la conclusión se sugiere a sí misma: abrir la pestaña personalizada del navegador para la pantalla de consentimiento.

Si alguno de ustedes tiene argumentos a favor de WebView en lugar de la pestaña personalizada del navegador, escríbalo en los comentarios, lo agradeceré.

Esquema seguro de Mobile OAuth 2.0


Utilizaremos el esquema de concesión de código de autorización porque nos permite agregar un code_challenge y protegernos de un ataque de intercepción de código.


Imagen tomada de https://tools.ietf.org/html/rfc8252#section-4.1

La solicitud de código (pasos 1-2) se verá así:

https://o2.mail.ru/code?
redirect_uri=com.mail.cloud.app%3A%2F%2Foauth&
anti_csrf=927489cb2fcdb32e302713f6a720397868b71dd2128c734181983f367d622c24& code_challenge=ZjYxNzQ4ZjI4YjdkNWRmZjg4MWQ1N2FkZjQzNGVkODE1YTRhNjViNjJjMGY5MGJjNzdiOGEzMDU2ZjE3NGFiYw%3D%3D&
code_challenge_method=S256&
scope=email%2Cid&
response_type=code&
client_id=984a644ec3b56d32b0404777e1eb73390c

En el paso 3, el navegador recibe una respuesta redirigida:

com.mail.cloud.app://outh?
code=b57b236c9bcd2a61fcd627b69ae2d7a6eb5bc13f2dc25311348ee08df43bc0c4&
anti_csrf=927489cb2fcdb32e302713f6a720397868b71dd2128c734181983f367d622c24


En el paso 4, el navegador abre el esquema URI personalizado y pasa el code y el token CSRF a la aplicación cliente.

Solicitud de access_token (paso 5):

https://o2.mail.ru/token?
code_verifier=e61748f28b7d5daf881d571df434ed815a4a65b62c0f90bc77b8a3056f174abc&
code=b57b236c9bcd2a61fcd627b69ae2d7a6eb5bc13f2dc25311348ee08df43bc0c4&
client_id=984a644ec3b56d32b0404777e1eb73390c

El último paso devuelve una respuesta con access_token .

En general, el esquema anterior es seguro, pero también hay casos especiales en los que OAuth 2.0 puede hacerse más simple y un poco más seguro.

Android IPC


Android tiene un mecanismo para el intercambio de datos bidireccional entre procesos: IPC (comunicación entre procesos). Se prefiere IPC sobre el esquema URI personalizado por dos razones:

  1. Una aplicación que abre un canal IPC puede verificar la autenticidad de una aplicación abierta mediante su certificado. Lo contrario también es cierto: una aplicación abierta puede verificar la autenticidad de la aplicación que la abrió.
  2. Al enviar una solicitud a través de un canal IPC, el remitente puede recibir una respuesta a través del mismo canal. Junto con la verificación mutua (elemento 1), esto significa que ningún proceso de terceros puede interceptar access_token .



Por lo tanto, podemos usar la Subvención implícita y simplificar enormemente el esquema móvil OAuth 2.0. Sin code_challenge y tokens CSRF. Además, podremos protegernos del malware que imita a clientes legítimos para robar cuentas de usuario.

SDK del cliente


Además de implementar el esquema seguro de OAuth 2.0 móvil descrito anteriormente, el proveedor debe desarrollar un SDK para sus clientes. Esto facilitará la implementación de OAuth 2.0 en el lado del cliente y al mismo tiempo reducirá la cantidad de errores y vulnerabilidades.

Sacar conclusiones


Para los proveedores de OAuth 2.0, compilé la "Lista de verificación de Secure Mobile OAuth 2.0":

  1. Una base sólida es vital. En el caso de OAuth 2.0 móvil, la base es el esquema o protocolo que elegimos implementar. Al implementar su propio esquema OAuth 2.0, es fácil cometer un error. Otros ya han llenado los baches y han llegado a conclusiones, no hay nada de malo en aprender de sus errores e inmediatamente hacer una implementación segura. En general, el esquema OAuth 2.0 móvil más seguro es el de la sección ¿Qué hacer?
  2. Access_token y otros datos confidenciales: en iOS, en Llavero, en Android, en Almacenamiento interno. Estos repositorios están diseñados específicamente para tales fines. Si es necesario, puede usar el proveedor de contenido en Android, pero debe configurarse de manera segura.
  3. Code debe ser de una sola vez, con un tiempo de vida corto.
  4. Para protegerse contra la intercepción de código, use code_challenge .
  5. Para protegerse contra un ataque CSRF en el inicio de sesión, use tokens CSRF.
  6. No use WebView para la pantalla de consentimiento, use la pestaña personalizada del navegador.
  7. Client_secret inútil si no está almacenado en el backend. No se lo dé a clientes públicos.
  8. Use HTTPS en todas partes , con la prohibición de rebajar a HTTP.
  9. Siga las recomendaciones de criptografía (selección de cifrado, longitud del token, etc.) de los estándares . Puede copiar los datos y descubrir por qué se hizo de esa manera, pero no puede hacer su criptografía .
  10. Desde la aplicación del cliente, verifique a quién abre para OAuth 2.0, y desde la aplicación del proveedor, verifique quién lo abre para OAuth 2.0.
  11. Tenga en cuenta las vulnerabilidades habituales de OAuth 2.0 . Mobile OAuth 2.0 amplía y complementa el normal, por lo que nadie canceló la verificación de redirect_uri para ver las coincidencias exactas y otras recomendaciones para OAuth 2.0 regular.
  12. Asegúrese de proporcionar SDK a los clientes. El cliente tendrá menos errores y vulnerabilidades en el código, y será más fácil para él implementar su OAuth 2.0.

Que leer


  1. [RFC] OAuth 2.0 para aplicaciones nativas https://tools.ietf.org/html/rfc8252
  2. Google OAuth 2.0 para aplicaciones móviles y de escritorio https://developers.google.com/identity/protocols/OAuth2InstalledApp
  3. [RFC] Clave de prueba para el intercambio de código por parte de clientes públicos de OAuth https://tools.ietf.org/html/rfc7636
  4. Condición de carrera OAuth 2.0 https://hackerone.com/reports/55140
  5. [RFC] Modelo de amenaza OAuth 2.0 y consideraciones de seguridad https://tools.ietf.org/html/rfc6819
  6. Ataques en OAuth 2.0 normal https://sakurity.com/oauth
  7. [RFC] Protocolo de registro de cliente dinámico OAuth 2.0 https://tools.ietf.org/html/rfc7591

Agradecimientos


Gracias a todos los que ayudaron a escribir este artículo, especialmente Sergey Belov, Andrey Sumin, Andrey Labunts ( @isciurus ) y Daria Yakovleva.

Source: https://habr.com/ru/post/es417031/


All Articles