Segurança do Mobile OAuth 2.0



Olá pessoal! Sou Nikita Stupin, especialista em segurança da informação, Mail.Ru Mail. Há pouco tempo, conduzi uma pesquisa de vulnerabilidade no OAuth 2.0 para dispositivos móveis. Para criar um esquema OAuth 2.0 móvel seguro, não basta implementar o padrão em sua forma pura e verificar redirect_uri. É necessário levar em consideração as especificidades dos aplicativos móveis e aplicar mecanismos de proteção adicionais.

Neste artigo, quero compartilhar com você conhecimentos sobre ataques ao OAuth 2.0 para celular, sobre métodos de proteção e a implementação segura deste protocolo. Todos os componentes de proteção necessários, discutidos abaixo, são implementados no SDK mais recente para os clientes móveis do Mail.Ru Mail.

A natureza e função do OAuth 2.0


OAuth 2.0 é um protocolo de autorização que descreve como é seguro para um serviço de cliente acessar recursos do usuário em um provedor de serviços. Ao mesmo tempo, o OAuth 2.0 evita que o usuário digite uma senha fora do provedor de serviços: todo o processo é reduzido ao clicar no botão "Concordo em conceder acesso a ...".

Um provedor em termos de OAuth 2.0 é um serviço que possui dados do usuário e, com a permissão do usuário, fornece serviços de terceiros (clientes) com acesso seguro a esses dados. Um cliente é um aplicativo que deseja receber dados do usuário de um provedor.

Algum tempo após o lançamento do protocolo OAuth 2.0, os desenvolvedores comuns o adaptaram para autenticação, embora não tenha sido originalmente planejado para isso. A autenticação muda o vetor de ataque dos dados do usuário armazenados no provedor de serviços para as contas de usuário do serviço do usuário.

Não foi limitado apenas à autenticação. Na era dos aplicativos móveis e na exaltação da conversão, entrar no aplicativo com um único botão se tornou muito tentador. Os desenvolvedores colocam o OAuth 2.0 nos trilhos móveis. Naturalmente, poucas pessoas pensaram na segurança e nas especificidades dos aplicativos móveis: uma e outra vez e na produção. No entanto, o OAuth 2.0 geralmente não funciona bem fora dos aplicativos da Web: os mesmos problemas são observados nos aplicativos móveis e de desktop.

Vamos descobrir como criar um OAuth 2.0 móvel seguro.

Como isso funciona?


Lembre-se de que em dispositivos móveis, o cliente pode não ser um navegador, mas um aplicativo móvel sem back-end. Portanto, enfrentamos dois grandes problemas de segurança no OAuth 2.0 para celular:

  1. O cliente não é confiável.
  2. O comportamento de um redirecionamento de um navegador para um aplicativo móvel depende das configurações e aplicativos que o usuário instalou.

Aplicativo móvel é um cliente público


Para entender a raiz do primeiro problema, vamos ver como o OAuth 2.0 funciona no caso de interação servidor para servidor e, em seguida, compará-lo com o OAuth 2.0 no caso de interação cliente-servidor.

Nos dois casos, tudo começa com o fato de o cliente do serviço se registrar no provedor de serviços e receber client_id e, em alguns casos, client_secret . O valor client_id é público e é necessário para identificar o serviço do cliente, diferentemente do client_secret , cujo valor é privado. O processo de registro é descrito em mais detalhes na RFC 7591 .

O diagrama abaixo mostra a operação do OAuth 2.0 na comunicação entre servidores.


Imagem retirada de https://tools.ietf.org/html/rfc6749#section-1.2

Existem três estágios principais do protocolo OAuth 2.0:

  1. [Etapas AC] Obtenha o código de autorização (a seguir, simplesmente code ).
  2. [DE passos] Trocar code para access_token .
  3. Acesse o recurso usando access_token .

Analisaremos o recebimento do código em mais detalhes:

  1. [Etapa A] O cliente do serviço redireciona o usuário ao provedor de serviços.
  2. [Etapa B] O provedor de serviços solicita permissão do usuário para fornecer dados ao serviço ao cliente (seta B para cima). O usuário fornece acesso aos dados (seta B à direita).
  3. [Etapa C] O provedor de serviços retorna o code para o navegador do usuário, que redireciona o code o serviço ao cliente.

Vamos access_token como access_token mais detalhes:

  1. [Etapa D] O servidor do cliente envia uma solicitação para access_token . A solicitação inclui: code , client_secret e redirect_uri .
  2. [Etapa E] No caso de code válido, client_secret e redirect_uri , client_secret fornecido.

A solicitação para access_token é realizada de acordo com o esquema servidor para servidor; portanto, em geral, para roubar client_secret invasor deve invadir o servidor servidor-cliente ou o servidor do provedor de serviços.

Agora vamos ver como é o esquema do OAuth 2.0 em um dispositivo móvel sem back-end (interação cliente-servidor).


Imagem retirada de https://tools.ietf.org/html/rfc8252#section-4.1

O esquema geral é dividido nas mesmas três etapas principais:

  1. [etapas 1 a 4 da figura] Obtenha o code .
  2. [etapas 5 a 6 da figura] Troque o code por access_token .
  3. Acesse o recurso usando access_token .

No entanto, nesse caso, o aplicativo móvel também atua como um servidor, o que significa que o client_secret será client_secret dentro do aplicativo. Isso leva ao fato de que em dispositivos móveis é impossível manter o lient_secret segredo de um invasor. client_secret duas maneiras de client_secret ao aplicativo: para filtrar o tráfego do aplicativo para o servidor ou fazer a engenharia reversa do aplicativo. Ambos os métodos são fáceis de implementar, portanto, client_secret inútil em dispositivos móveis.

Em relação ao esquema cliente para servidor, você pode ter uma pergunta: "por que não obter imediatamente o access_token ?". Parece, por que precisamos de uma etapa extra? Além disso, existe um esquema de concessão implícita no qual o cliente recebe imediatamente um access_token . Embora possa ser usado em alguns casos, veremos abaixo que a concessão implícita não é adequada para o OAuth 2.0 móvel seguro.

Redirecionar em dispositivos móveis


Em geral, para um redirecionamento de um navegador para um aplicativo em dispositivos móveis, os mecanismos Custom URI Scheme e AppLink são usados. Nenhum desses mecanismos em sua forma pura é tão confiável quanto um redirecionamento de navegador.

O esquema de URI personalizado (ou link direto) é usado da seguinte maneira: o desenvolvedor define o esquema de aplicativo antes da montagem. O esquema pode ser arbitrário, enquanto no mesmo dispositivo vários aplicativos com o mesmo esquema podem ser instalados. Tudo é bem simples quando cada aplicativo no dispositivo corresponde a um aplicativo. Mas e se dois aplicativos registrassem o mesmo circuito no mesmo dispositivo? Como o sistema operacional pode determinar qual dos dois aplicativos abrir ao acessar o esquema de URI personalizado? O Android mostrará uma janela com a opção de aplicativo na qual você deseja abrir um link. No iOS, o comportamento não está definido , o que significa que qualquer um dos dois aplicativos pode ser aberto. Nos dois casos, um invasor pode interceptar código ou access_token .

O AppLink, ao contrário do Esquema URI personalizado, é garantido para abrir o aplicativo certo, mas esse mecanismo tem várias desvantagens:

  1. Cada cliente de serviço deve passar independentemente no procedimento de verificação .
  2. Os usuários do Android podem desativar o AppLink para um aplicativo específico nas configurações.
  3. O Android abaixo de 6.0 e o iOS abaixo de 9.0 não são compatíveis com o AppLink.

As desvantagens acima do AppLink, em primeiro lugar, aumentam o limite de entrada para serviços potenciais de clientes e, em segundo lugar, podem levar ao fato de que, em determinadas circunstâncias, o usuário não trabalha com o OAuth 2.0. Isso torna o AppLink inadequado para substituir os redirecionamentos do navegador no protocolo OAuth 2.0.

Ok, o que atacar?


Os problemas do OAuth 2.0 para dispositivos móveis também deram origem a ataques específicos. Vamos ver o que são e como funcionam.

Ataque de interceptação de código de autorização


Dados iniciais: um aplicativo legítimo (cliente OAuth 2.0) e um aplicativo mal-intencionado que registrou o mesmo esquema que o legítimo são instalados no dispositivo do usuário. A figura abaixo mostra o esquema de ataque.


Imagem retirada de https://tools.ietf.org/html/rfc7636#section-1

Aqui está o problema: na etapa 4, o navegador retorna o code ao aplicativo por meio do Esquema URI personalizado, para que o code possa ser interceptado pelo malware (porque registrou o mesmo esquema do aplicativo legítimo). Depois disso, o malware altera o code para access_token e obtém acesso aos dados do usuário.

Como se proteger? Em alguns casos, mecanismos de comunicação entre processos podem ser usados; falaremos sobre eles abaixo. No caso geral, você precisa aplicar um esquema chamado Proof Key for Code Exchange . Sua essência é refletida no diagrama abaixo.


Imagem retirada de https://tools.ietf.org/html/rfc7636#section-1.1

Nas solicitações do cliente, existem vários parâmetros adicionais: code_verifier , code_challenge (no t(code_verifier) ) e code_challenge_method (no diagrama t_m ).

Code_verifier é um número aleatório de pelo menos 256 bits que é usado apenas uma vez . Ou seja, para cada solicitação de code cliente deve gerar um novo code_verifier .

Code_challenge_method é o nome de uma função de conversão, na maioria das vezes SHA-256.

Code_challenge é um code_verifier ao qual a conversão code_challenge_method foi code_challenge_method e codificada na URL Safe Base64.

A conversão de code_verifier em code_challenge necessária para proteger contra vetores de ataque com base na interceptação de code_verifier (por exemplo, nos logs do sistema do dispositivo) ao solicitar code .

Se o dispositivo do usuário não suportar SHA-256, um downgrade será permitido até que a conversão do code_verifier esteja ausente . Em todos os outros casos, você deve usar o SHA-256.

O esquema funciona da seguinte maneira:

  1. O cliente gera um code_verifier e se lembra dele.
  2. O cliente seleciona code_challenge_method e obtém code_challenge no code_verifier .
  3. [Etapa A] O cliente solicita code , com code_challenge e code_challenge_method adicionados à solicitação.
  4. [Etapa B] O provedor se lembra do code_challenge e code_challenge_method no servidor e retorna o code cliente.
  5. [Etapa C] O cliente solicita o access_token , com o access_token sendo adicionado à code_verifier .
  6. O provedor recebe o code_challenge do code_challenge recebido e depois o verifica no code_challenge , do qual ele se lembrava.
  7. [Etapa D] Se os valores corresponderem, o provedor emitirá um access_token cliente.

Vamos code_challenge por que code_challenge permite que code_challenge se proteja de um ataque de interceptação de código. Para fazer isso, passaremos pelas etapas de obtenção do access_token .

  1. Primeiro, um aplicativo legítimo solicita o code ( code_challenge e code_challenge_method enviados junto com a solicitação ).
  2. O malware intercepta o code (mas não o code_challenge , porque não há code_challenge na resposta ).
  3. O malware solicita access_token (com code válido, mas sem code_verifier válido).
  4. O servidor percebe a incompatibilidade code_challenge e gera um erro.

Observe que o invasor não tem a capacidade de adivinhar o code_verifier (aleatório 256 bits!) Ou encontre-o em algum lugar nos logs ( code_verifier é transmitido uma vez).

Se tudo isso for reduzido a uma frase, o code_challenge permitirá que o provedor de serviços responda à pergunta: “o access_token está access_token solicitado pelo mesmo aplicativo cliente que solicitou o code ou por outro?”.

CSRF do OAuth 2.0


Em dispositivos móveis, o OAuth 2.0 é frequentemente usado como um mecanismo de autenticação. Como lembramos, a autenticação por meio do OAuth 2.0 difere da autorização, pois as vulnerabilidades do OAuth 2.0 afetam os dados do usuário no lado do cliente de serviço, e não o provedor de serviços. Como resultado, o ataque do CSRF ao OAuth 2.0 permite que você roube a conta de outra pessoa.

Considere um ataque de CSRF contra o OAuth 2.0 usando o exemplo do aplicativo cliente de táxi e do provedor provider.com. Primeiro, um invasor faz logon no attacker@provider.com em seu dispositivo e recebe um code para o táxi. Depois disso, o invasor interrompe o processo do OAuth 2.0 e gera um link:

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

Em seguida, o atacante envia um link para a vítima, por exemplo, sob o disfarce de uma carta ou SMS da administração do táxi. A vítima access_token link, um aplicativo de táxi é aberto no telefone, que recebe access_token e, como resultado, a vítima acaba na conta de táxi do atacante . Desconhecendo a captura, a vítima usa esta conta: faz viagens, insere seus dados, etc.

Agora, um invasor pode fazer login na conta de táxi da vítima a qualquer momento, porque está vinculado a attacker@provider.com . O ataque CSRF no login permitiu roubar uma conta.

Os ataques de CSRF geralmente são protegidos com um token de CSRF (também chamado de state ), e o OAuth 2.0 não é uma exceção. Como usar o token CSRF:

  1. O aplicativo cliente gera e armazena o token CSRF no dispositivo móvel do usuário.
  2. O aplicativo cliente inclui o token CSRF na solicitação de code .
  3. O servidor retorna o mesmo token CSRF na resposta junto com o código.
  4. O aplicativo cliente compara o token CSRF recebido e armazenado. Se os valores corresponderem, o processo continuará.

Requisitos de token CSRF: com exceção de pelo menos 256 bits, obtidos de uma boa fonte de sequências pseudo-aleatórias.

Em resumo, o token CSRF permite que o aplicativo cliente responda à pergunta: "eu estava começando a obter access_token , ou alguém está tentando me enganar?"

Malware que finge ser um cliente legítimo


Alguns malwares podem imitar aplicativos legítimos e gerar uma tela de consentimento em seu nome (tela de consentimento é uma tela na qual o usuário vê: "Concordo em conceder acesso a ..."). O usuário desatento pode clicar em "permitir" e, como resultado, o malware obtém acesso aos dados do usuário.

Android e iOS fornecem mecanismos para verificação mútua de aplicativos. O aplicativo provedor pode verificar a legitimidade do aplicativo cliente e vice-versa.

Infelizmente, se o mecanismo OAuth 2.0 usar um fluxo por meio de um navegador, você não poderá se defender contra esse ataque.

Outros ataques


Examinamos os ataques exclusivos do OAuth 2.0 para celular. No entanto, não se esqueça dos ataques ao OAuth 2.0 regular: falsificação de redirect_uri , interceptação de tráfego em uma conexão insegura etc. Você pode ler mais sobre eles aqui .

O que fazer?


Aprendemos como o protocolo OAuth 2.0 funciona e descobrimos quais vulnerabilidades existem nas implementações desse protocolo em dispositivos móveis. Agora vamos montar um esquema OAuth 2.0 móvel seguro de peças individuais.

Bom, ruim OAuth 2.0


Vamos começar com como aumentar corretamente a tela de consentimento. Em dispositivos móveis, existem duas maneiras de abrir uma página da Web a partir de um aplicativo nativo (exemplos de aplicativos nativos: Mail.Ru Mail, VK, Facebook).



O primeiro método é chamado de Aba personalizada do navegador (na figura à esquerda). Nota : a guia Personalizada do navegador no Android chama-se Guia personalizada do Chrome e no iOS SafariViewController. Na verdade, essa é uma guia normal do navegador, exibida diretamente no aplicativo, ou seja, Não há alternância visual entre aplicativos.

O segundo método é chamado “raise WebView” (na imagem à direita), em relação ao OAuth 2.0 para dispositivos móveis, considero ruim.

O WebView é um navegador independente para um aplicativo nativo.

Um " navegador independente" significa que o WebView não permite acesso a cookies, armazenamento, cache, histórico e outros dados dos navegadores Safari e Chrome. O inverso também é verdadeiro: o Safari e o Chrome não podem acessar os dados do WebView.

Navegador para um aplicativo nativo ” significa que o aplicativo nativo que criou o WebView tem acesso total a cookies, armazenamento, cache, histórico e outros dados do WebView.

Agora imagine: o usuário pressiona o botão "fazer login usando ..." e o WebView do aplicativo malicioso solicita seu nome de usuário e senha ao provedor de serviços.

Falha ao mesmo tempo em todas as frentes:

  1. O usuário digita o nome de usuário e a senha da conta do provedor de serviços no aplicativo, o que pode facilmente roubar esses dados.
  2. O OAuth 2.0 foi desenvolvido originalmente para não inserir um nome de usuário e senha de um provedor de serviços.
  3. O usuário se acostuma a digitar o login e a senha em qualquer lugar, a probabilidade de phishing aumenta.

Dado que todos os argumentos são contra o WebView, a conclusão sugere-se: aumente a guia Personalização do navegador para obter a tela de consentimento.

Se algum de vocês tiver argumentos a favor do WebView em vez da guia Personalizada do navegador, escreva sobre isso nos comentários, ficarei muito agradecido.

Esquema do Secure Mobile OAuth 2.0


Usaremos o esquema de concessão de código de autorização porque ele nos permite adicionar um code_challenge e code_challenge proteger de um ataque de interceptação de código.


Imagem retirada de https://tools.ietf.org/html/rfc8252#section-4.1

A solicitação de código (etapas 1-2) terá a seguinte aparência:

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

Na etapa 3, o navegador recebe uma resposta redirecionada:

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


Na etapa 4, o navegador abre o esquema de URI personalizado e passa o code e o token CSRF para o aplicativo cliente.

Solicitação de access_token (etapa 5):

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

A última etapa retorna uma resposta com access_token .

Em geral, o esquema acima é seguro, mas também há casos especiais em que o OAuth 2.0 pode ser simplificado e um pouco mais seguro.

Android IPC


O Android possui um mecanismo para troca de dados bidirecional entre processos: IPC (comunicação entre processos). O IPC é preferível ao esquema de URI personalizado por dois motivos:

  1. Um aplicativo que abre um canal IPC pode verificar a autenticidade de um aplicativo aberto por seu certificado. O inverso também é verdadeiro: um aplicativo aberto pode verificar a autenticidade do aplicativo que o abriu.
  2. Ao enviar uma solicitação através de um canal IPC, o remetente pode receber uma resposta através do mesmo canal. Juntamente com a verificação mútua (item 1), isso significa que nenhum processo de terceiros pode interceptar o access_token .



Assim, podemos usar a concessão implícita e simplificar bastante o esquema OAuth 2.0 para dispositivos móveis. Não code_challenge tokens code_challenge e CSRF. Além disso, poderemos nos proteger de malware que imita clientes legítimos, a fim de roubar contas de usuário.

SDK do cliente


Além de implementar o esquema OAuth 2.0 móvel seguro descrito acima, o provedor deve desenvolver um SDK para seus clientes. Isso facilitará a implementação do OAuth 2.0 no lado do cliente e, ao mesmo tempo, reduzirá o número de erros e vulnerabilidades.

Tirar conclusões


Para os provedores do OAuth 2.0, compilei a "Lista de verificação do Secure Mobile OAuth 2.0":

  1. Uma base sólida é vital. No caso do OAuth 2.0 para dispositivos móveis, a base é o esquema ou protocolo que escolhemos implementar. Ao implementar seu próprio esquema OAuth 2.0, é fácil cometer um erro. Outros já preencheram as lacunas e tiraram conclusões, não há nada de errado em aprender com seus erros e fazer imediatamente uma implementação segura. Em geral, o esquema OAuth 2.0 móvel mais seguro é o da seção O que fazer?
  2. Access_token e outros dados confidenciais: em iOS - em Keychain, em Android - em Armazenamento Interno. Esses repositórios são projetados especificamente para esses fins. Se necessário, você pode usar o provedor de conteúdo no Android, mas ele deve ser configurado com segurança.
  3. Code deve ser único, com uma vida útil curta.
  4. Para se proteger contra a interceptação de código, use code_challenge .
  5. Para se proteger contra um ataque CSRF no logon, use tokens CSRF.
  6. Não use o WebView para obter a tela de consentimento, use a Aba personalizada do navegador.
  7. Client_secret inútil se não estiver armazenado no back-end. Não o entregue a clientes públicos.
  8. Use HTTPS em qualquer lugar , com a proibição de fazer o downgrade para HTTP.
  9. Siga as recomendações de criptografia (seleção de cifra, comprimento do token etc.) dos padrões . Você pode copiar os dados e descobrir por que isso foi feito dessa maneira, mas não pode fazer sua criptografia .
  10. No aplicativo cliente, verifique quem você abre para o OAuth 2.0 e, no aplicativo provedor, verifique quem abre o OAuth 2.0.
  11. Esteja ciente das vulnerabilidades usuais do OAuth 2.0 . O OAuth 2.0 para dispositivos móveis estende e complementa o padrão, portanto ninguém cancelou a verificação redirect_uri para correspondências exatas e outras recomendações para o OAuth 2.0 regular.
  12. Certifique-se de fornecer SDKs aos clientes. O cliente terá menos bugs e vulnerabilidades no código e será mais fácil para ele implementar o OAuth 2.0.

O que ler


  1. [RFC] OAuth 2.0 para aplicativos nativos https://tools.ietf.org/html/rfc8252
  2. Google OAuth 2.0 para aplicativos para dispositivos móveis e computadores https://developers.google.com/identity/protocols/OAuth2InstalledApp
  3. [RFC] Chave de prova para troca de código por clientes públicos do OAuth https://tools.ietf.org/html/rfc7636
  4. Condição de corrida do OAuth 2.0 https://hackerone.com/reports/55140
  5. [RFC] Modelo de ameaça do OAuth 2.0 e considerações de segurança https://tools.ietf.org/html/rfc6819
  6. Ataques ao OAuth 2.0 regular https://sakurity.com/oauth
  7. [RFC] Protocolo de registro dinâmico de cliente OAuth 2.0 https://tools.ietf.org/html/rfc7591

Agradecimentos


Obrigado a todos que ajudaram a escrever este artigo, especialmente Sergey Belov, Andrey Sumin, Andrey Labunts ( @isciurus ) e Daria Yakovleva.

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


All Articles