Segurança do OAuth 2.0 móvel

imagem

A popularidade dos aplicativos móveis continua a crescer. O mesmo acontece com o protocolo OAuth 2.0 em aplicativos móveis. Não é suficiente implementar o padrão, como é fazer o protocolo OAuth 2.0 seguro lá. É preciso considerar as especificidades dos aplicativos móveis e aplicar alguns mecanismos de segurança adicionais.

Neste artigo, quero compartilhar os conceitos de ataques móveis do OAuth 2.0 e mecanismos de segurança usados ​​para evitar esses problemas. Os conceitos descritos não são novos, mas há uma falta de informações estruturadas sobre este tópico. O principal objetivo do artigo é preencher essa lacuna.

Natureza e finalidade do OAuth 2.0


OAuth 2.0 é um protocolo de autorização que descreve uma maneira de um serviço de cliente obter um acesso seguro aos recursos do usuário em um provedor de serviços. Graças ao OAuth 2.0, o usuário não precisa digitar sua senha fora do provedor de serviços: todo o processo é reduzido ao clicar no botão "Concordo em fornecer acesso a ...".

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

Logo após o lançamento do protocolo OAuth 2.0, ele foi adaptado para autenticação , embora não fosse para isso. O uso do OAuth 2.0 para autenticação muda um vetor de ataque dos dados armazenados no provedor de serviços para as contas de usuário do serviço ao cliente.

Mas a autenticação era apenas o começo. Em tempos de aplicativos móveis e glorificação de conversões, acessar um aplicativo com apenas um botão parecia bom. Os desenvolvedores adaptaram o OAuth 2.0 para uso móvel. Obviamente, muitos não se preocupam com a segurança e os detalhes dos aplicativos móveis: zap e na produção em que foram! Por outro lado, o OAuth 2.0 não funciona bem fora dos aplicativos da Web: existem os mesmos problemas nos aplicativos para celular e para desktop.

Então, vamos descobrir como tornar o OAuth 2.0 móvel seguro.

Como isso funciona?


Existem dois principais problemas de segurança do OAuth 2.0 para dispositivos móveis:

  1. Cliente não confiável. Alguns aplicativos móveis não possuem back-end para o OAuth 2.0, portanto, a parte do cliente do fluxo do protocolo fica no dispositivo móvel.
  2. Os redirecionamentos de um navegador para um aplicativo móvel se comportam de maneira diferente, dependendo das configurações do sistema, da ordem em que os aplicativos são instalados e de outras formas mágicas.

Vamos analisar em profundidade essas questões.

Aplicativo móvel é um cliente público


Para entender as raízes e as consequências 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 os registros do serviço ao cliente no serviço do provedor e recebe client_id e , em alguns casos , client_secret. client_id , client_secret. client_id é um valor público e é necessário para a identificação do serviço ao cliente, em oposição ao valor client_secret , que é privado. Você pode ler mais sobre o processo de registro na RFC 7591 .

O esquema abaixo mostra o modo como o OAuth 2.0 opera em caso de interação servidor a servidor.


Origem da imagem: https://tools.ietf.org/html/rfc6749#section-1.2

O protocolo OAuth 2.0 pode ser dividido em três etapas principais:

  1. [etapas AC] Receba um code authorization_code (daqui em diante, code ).
  2. [etapas DE] Troca de code para access_token .
  3. Obtenha recursos via access_token .


Vamos elaborar o processo de obtenção code valor do code :

  1. [Etapa A] O cliente redireciona o usuário para o provedor de serviços.
  2. [Etapa B] O provedor de serviços solicita permissão do usuário para fornecer ao cliente os dados (seta B para cima). O usuário fornece acesso a 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 para o cliente.

Vamos falar mais sobre o processo de obter access_token :

  1. [Etapa D] O servidor cliente envia uma solicitação para access_token . Code , client_secret e redirect_uri estão incluídos na solicitação.
  2. [Etapa E] No caso de code válido, client_secret e redirect_uri , access_token é fornecido.

A solicitação para access_token é feita de acordo com o esquema servidor para servidor: portanto, em geral, o invasor precisa hackear o servidor de serviço ao cliente ou o servidor do provedor de serviços para roubar o access_token .

Agora, vejamos o esquema móvel do OAuth 2.0 sem back-end (interação cliente-servidor).


Origem da imagem: https://tools.ietf.org/html/rfc8252#section-4.1

O esquema principal é dividido nas mesmas etapas principais:

  1. [etapas 1 a 4 na imagem] Obtenha code .
  2. [etapas 5 a 6 da figura] Troque code para access_token
  3. Obtenha acesso a recursos via access_token

No entanto, nesse caso, o aplicativo móvel também possui as funções do servidor; portanto, client_secret seria incorporado ao aplicativo. Como resultado, o client_secret não pode ser mantido escondido do invasor em dispositivos móveis. O client_secret incorporado pode ser extraído de duas maneiras: analisando o tráfego do aplicativo para o servidor ou fazendo engenharia reversa. Ambos podem ser facilmente implementados, e é por isso que client_secret é inútil em dispositivos móveis.

Você pode perguntar: "Por que não temos acesso ao access_token imediatamente?" Você pode pensar que esta etapa extra é desnecessária. Além disso, existe o esquema de concessão implícita que permite que um cliente receba access_token imediatamente. Mesmo assim, ele pode ser usado em alguns casos, o Implicit Grant não funcionaria para o OAuth 2.0 móvel seguro.

Redirecionamento em dispositivos móveis


Em geral, o esquema URI personalizado e os mecanismos AppLink são usados ​​para redirecionar do navegador para o aplicativo. Nenhum desses mecanismos pode ser tão seguro quanto o navegador redireciona por si próprio.

O esquema de URI personalizado (ou link direto) é usado da seguinte maneira: um desenvolvedor determina um esquema de aplicativo antes da implantação. O esquema pode ser qualquer, e um dispositivo pode ter vários aplicativos com o mesmo esquema.

Isso facilita as coisas quando todos os esquemas de um dispositivo correspondem a um aplicativo. Mas e se dois aplicativos registrarem o mesmo esquema em um dispositivo? Como o sistema operacional decide qual aplicativo abrir quando contatado pelo esquema URI personalizado? O Android mostrará uma janela com a escolha de um aplicativo e um link a seguir. O iOS não possui um procedimento para isso e, portanto, qualquer aplicativo pode ser aberto. De qualquer forma, o invasor tem a chance de interceptar o código ou acessar o token .

Diferente do esquema de URI personalizado, o AppLink garante a abertura do aplicativo certo, mas esse mecanismo possui várias falhas:

  1. Todo cliente de serviço deve passar pelo procedimento de verificação .
  2. Os usuários do Android podem desativar o AppLink para um aplicativo específico nas configurações.
  3. Versões Android anteriores à 6.0 e versões iOS anteriores à 9.0 não são compatíveis com o AppLink.

Todas essas falhas do AppLink aumentam a curva de aprendizado de possíveis clientes de serviço e podem resultar em falha do OAuth 2.0 do usuário em algumas circunstâncias. É por isso que muitos desenvolvedores não escolhem o mecanismo AppLink como substituto para o redirecionamento do navegador no protocolo OAuth 2.0.

OK, o que há para atacar?


Os problemas do Mobile OAuth 2.0 criaram alguns ataques específicos. Vamos ver o que são e como funcionam.

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


Vamos considerar a situação em que o dispositivo do usuário possui um aplicativo legítimo (cliente OAuth 2.0) e um aplicativo malicioso que registrou o mesmo esquema que o legítimo. A imagem abaixo mostra o esquema de ataque.


Origem da imagem https://tools.ietf.org/html/rfc7636#section-1

Aqui está o problema: na quarta etapa, o navegador retorna o code no aplicativo via Custom URI Scheme e, portanto, o code pode ser interceptado por um aplicativo mal-intencionado (já que ele registrou o mesmo esquema que um aplicativo legítimo). Em seguida, o aplicativo malicioso altera o code para access_token e recebe acesso aos dados do usuário.

Qual é a proteção? Em alguns casos, você pode usar a comunicação entre processos; falaremos sobre isso mais tarde. Em geral, você precisa de um esquema chamado Proof Key for Code Exchange . Está descrito no esquema abaixo.


Origem da imagem: https://tools.ietf.org/html/rfc7636#section-1.1

A solicitação do cliente possui vários parâmetros extras: code_verifier , code_challenge (no esquema t(code_verifier) ) e code_challenge_method (no esquema t_m ).

Code_verifier - é um número aleatório com um comprimento mínimo de 256 bits , usado apenas uma vez . Portanto, um cliente deve gerar um novo code_verifier para cada solicitação de code .

Code_challenge_method - este é um nome de uma função de conversão, principalmente SHA-256.

Code_challenge - é o code_verifier ao qual a conversão code_challenge_method foi aplicada e codificada no URL Safe Base64.

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

Caso um dispositivo de usuário não suporte SHA-256, um client is allowed to use plain conversion of code_verifier . Em todos os outros casos, o SHA-256 deve ser usado.

É assim que este esquema funciona:

  1. O cliente gera o code_verifier e o memoriza.
  2. O cliente escolhe code_challenge_method e recebe code_challenge do code_verifier .
  3. [Etapa A] O cliente solicita code , com code_challenge e code_challenge_method adicionados à solicitação.
  4. [Etapa B] O provedor armazena code_challenge e code_challenge_method no servidor e retorna o code para um cliente.
  5. [Etapa C] O cliente solicita o access_token , com o code_verifier adicionado a ele.
  6. O provedor recebe code_challenge do code_challenge recebido e o compara ao code_challenge que ele salvou.
  7. [Etapa D] Se os valores corresponderem, o provedor access_token cliente o acesso.

Para entender por que code_challenge interceptação de código, vamos ver como o fluxo do protocolo se parece da perspectiva do invasor.

  1. Primeiro, o code solicitações legítimas de aplicativos ( code_challenge e code_challenge_method são enviados junto com a solicitação ).
  2. O aplicativo malicioso intercepta o code (mas não o code_challenge , pois o código _challenge não está na resposta).
  3. Aplicativo malicioso solicita access_token (com code válido, mas sem code_verifier válido).
  4. O servidor percebe incompatibilidade de code_challenge e gera uma mensagem de erro.

Observe que o invasor não consegue adivinhar o code_verifier (valor aleatório de 256 bits!) Ou encontra-o em algum lugar nos logs (desde que a primeira solicitação realmente transmitiu code_challenge ).

Portanto, code_challenge responde à pergunta do provedor de serviços: "O access_token é solicitado pelo mesmo cliente de aplicativo que solicitou o code ou um code diferente?".

CSRF do OAuth 2.0


O OAuth 2.0 CSRF é relativamente inofensivo quando o OAuth 2.0 é usado para autorização. É uma história completamente diferente quando o OAuth 2.0 é usado para autenticação. Nesse caso, o OAuth 2.0 CSRF geralmente leva à aquisição de contas.

Vamos falar mais sobre o ataque CSRF em conformidade com o OAuth 2.0 por meio do exemplo de cliente de aplicativo de táxi e provedor provider.com. Primeiro, um invasor em seu próprio dispositivo efetua login na conta attacker@provider.com e recebe o code para o táxi. Em seguida, ele interrompe o processo do OAuth 2.0 e gera um link:

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

Em seguida, o atacante envia esse link para a vítima, por exemplo, na forma de um email ou mensagem de texto de um táxi. A vítima clica no link, o aplicativo de táxi é aberto e recebe access_token . Como resultado, eles se encontram na conta de táxi do atacante . Sem saber disso, a vítima usa esta conta: faça viagens, insira dados pessoais etc.

Agora, o invasor pode fazer login na conta de táxi da vítima a qualquer momento, pois está vinculada a attacker@provider.com . O ataque de login do CSRF permitiu ao infrator roubar uma conta.

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

  1. O aplicativo cliente gera e salva o token CSRF no dispositivo móvel de um cliente.
  2. O aplicativo cliente inclui o token CSRF na solicitação de acesso ao code .
  3. O servidor retorna o mesmo token CSRF com o code em sua resposta.
  4. O aplicativo cliente compara os tokens CSRF recebidos e salvos. Se seus valores coincidirem, o processo continuará.

Requisitos de token CSRF: o nonce deve ter pelo menos 256 bits e ser recebido de uma boa fonte de sequências pseudo-aleatórias.

Em poucas palavras, o token CSRF permite que um cliente de aplicativo responda à seguinte pergunta: "Fui eu quem iniciou a solicitação access_token ou alguém está tentando me enganar?".

Segredo do cliente codificado


Às vezes, aplicativos móveis sem back-end armazenam valores client_id e client_secret codificados. Claro que eles podem ser facilmente extraídos pelo aplicativo de engenharia reversa.

O impacto da exposição de client_id e client_secret depende muito de quanto fornecedor de serviços de confiança coloca em determinado par client_id , client_secret . Um deles é usado apenas para distinguir um cliente do outro, enquanto outros abrem pontos finais de API ocultos ou estabelecem limites de taxa mais baixos para alguns clientes.

O artigo Por que as chaves e segredos da API do OAuth não são seguros em aplicativos para dispositivos móveis detalha mais esse tópico.

Aplicativo malicioso que atua como um cliente legítimo


Alguns aplicativos maliciosos podem imitar os legítimos e exibir uma tela de consentimento em seu nome (uma tela de consentimento é uma tela em que o usuário vê: "Concordo em fornecer acesso a ..."). O usuário pode clicar em "permitir" e fornecer seus dados ao aplicativo mal-intencionado.

Android e iOS fornecem os mecanismos dos aplicativos para verificação cruzada. Um provedor de aplicativos pode garantir que um aplicativo cliente seja legítimo e vice-versa.

Infelizmente, se o mecanismo OAuth 2.0 usa um encadeamento via navegador, é impossível se defender contra esse ataque.

Outros ataques


Examinamos de perto os ataques exclusivos do OAuth 2.0 para celular. No entanto, não vamos esquecer a OAuth 2.0 original: substituição redirect_uri , interceptação de tráfego por conexão não segura etc. Você pode ler mais sobre isso aqui .

Como fazê-lo com segurança?


Aprendemos como o protocolo OAuth 2.0 funciona e quais vulnerabilidades ele possui em dispositivos móveis. Agora, vamos juntar as partes separadas para ter um esquema seguro do OAuth 2.0 para dispositivos móveis.

Bom, ruim OAuth 2.0


Vamos começar da maneira correta de usar a tela de consentimento. Os dispositivos móveis têm duas maneiras de abrir uma página da web em um aplicativo móvel.



A primeira maneira é através da guia Personalizada do navegador (à esquerda na imagem). Nota : a aba personalizada do navegador para Android é chamada de aba personalizada do Chrome e para iOS - SafariViewController. É apenas uma guia do navegador exibida no aplicativo: não há alternância visual entre os aplicativos.

A segunda maneira é via WebView (à direita na foto) e considero ruim em relação ao OAuth 2.0 para celular.

O WebView é um navegador incorporado para um aplicativo móvel.

" Navegador incorporado " significa que o WebView é proibido para cookies, armazenamento, cache, histórico e outros dados do Safari e Chrome. O inverso também está correto: o Safari e o Chrome não podem acessar os dados do WebView.

" Navegador de aplicativo móvel " significa que um aplicativo móvel que executa o WebView tem acesso total a cookies, armazenamento, cache, histórico e outros dados do WebView.

Agora, imagine: um usuário clica em "entrar com ..." e o WebView de um aplicativo mal-intencionado solicita seu login e senha ao provedor de serviços.

Falha épica:

  1. O usuário digita seu login e senha para a conta do provedor de serviços no aplicativo, que pode facilmente roubar esses dados.
  2. O Outh 2.0 foi desenvolvido inicialmente para não inserir o login e a senha do provedor de serviços.

    O usuário se acostuma a digitar seu login e senha em qualquer lugar, aumentando assim a possibilidade de pesca .

Considerando todos os contras do WebView, uma conclusão óbvia se oferece: use a Aba personalizada do navegador para obter a tela de consentimento.

Se alguém tiver argumentos a favor do WebView em vez da guia Personalizada do navegador, agradeceria se você escrever sobre isso nos comentários.

Esquema OAuth 2.0 móvel seguro


Usaremos o esquema de concessão de código de autorização, pois ele permite adicionar code_challenge , além de state e defender contra um ataque de interceptação de código e o OAuth 2.0 CSRF.


Origem da imagem: https://tools.ietf.org/html/rfc8252#section-4.1

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

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

Na etapa 3, o navegador obtém uma resposta com o redirecionamento:

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

Na etapa 4, o navegador abre o esquema de URI personalizado e passa o token CSRF para um aplicativo cliente.
solicitação access_token (etapa 5):

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

A última etapa traz uma resposta com access_token .

Esse esquema geralmente é seguro, mas há casos especiais em que o OAuth 2.0 pode ser mais simples e mais seguro.

Android IPC


O Android possui um mecanismo de comunicação de dados bidirecional entre processos: IPC (comunicação entre processos). O IPC é melhor que o esquema de URI personalizado por dois motivos:

  1. Um aplicativo que abre o canal IPC pode confirmar a autenticidade de um aplicativo que está abrindo pelo certificado. O inverso também é verdadeiro: o aplicativo aberto pode confirmar a autenticidade do aplicativo que o abriu.
  2. Se um remetente enviar uma solicitação pelo canal IPC, ele poderá receber uma resposta pelo mesmo canal. Juntamente com a verificação cruzada (item 1), significa que nenhum processo externo pode interceptar o access_token .



Portanto, podemos usar a concessão implícita para simplificar o esquema móvel do OAuth 2.0. Nenhum code_challenge e state também significam menos superfície de ataque. Também podemos reduzir os riscos de aplicativos mal-intencionados agirem como clientes legítimos tentando roubar as contas de usuário.

SDK para clientes


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

Conclusões


Deixe-me resumir para você. Aqui está a lista de verificação (básica) para provedores seguros de OAuth 2.0 para OAuth 2.0:

  1. Uma base sólida é crucial. No caso do OAuth 2.0 para dispositivos móveis, a base é um esquema ou protocolo escolhido para implementação. É fácil cometer erros ao implementar seu próprio esquema OAuth 2.0 . Outros já sofreram pancadas e aprenderam a lição; não há nada de errado em aprender com seus erros e fazer uma implementação segura de uma só vez. O esquema OAuth 2.0 móvel mais seguro é descrito em Como fazer isso com segurança ?
  2. Access_token e outros dados confidenciais devem ser armazenados no Keychain para iOS e no Internal Storage for Android. Esses armazenamentos foram desenvolvidos especificamente para isso. O Provedor de conteúdo pode ser usado no Android, mas deve ser configurado com segurança.
  3. Client_secret é inútil , a menos que seja armazenado no back-end. Não o entregue aos clientes públicos.
  4. Não use o WebView para obter a tela de consentimento; use a guia personalizada do navegador.
  5. Para se defender contra ataques de interceptação de código, use code_challenge .
  6. Para se defender do OAuth 2.0 CSRF, use state .
  7. Use HTTPS em qualquer lugar , com o downgrade proibido para HTTP. Aqui está uma demonstração de 3 minutos explicando o porquê (com exemplo de uma recompensa de bug).
  8. Siga os padrões de criptografia (escolha do algoritmo, comprimento dos tokens, etc.). Você pode copiar os dados e descobrir por que isso foi feito dessa maneira, mas não role sua própria criptografia.
  9. Code deve ser usado apenas uma vez, com uma vida útil curta.
  10. Do lado do cliente do aplicativo, verifique o que você abre para o OAuth 2.0; e do lado do provedor de aplicativos, verifique quem o abre para o OAuth 2.0.
  11. Lembre-se de vulnerabilidades comuns do OAuth 2.0 . O OAuth 2.0 para dispositivos móveis aumenta e completa o original, portanto, a verificação redirect_uri para uma correspondência exata e outras recomendações para o OAuth 2.0 original ainda estão em vigor.
  12. Você deve fornecer aos seus clientes o SDK. Eles terão menos bugs e vulnerabilidades e será mais fácil implementar o OAuth 2.0.

Leitura adicional


  1. "Vulnerabilidades do OAuth 2.0 para dispositivos móveis" https://www.youtube.com/watch?v=vjCF_O6aZIg
  2. Pesquisa de condição de corrida do OAuth 2.0 https://hackerone.com/reports/55140
  3. Quase tudo sobre o OAuth 2.0 em um só lugar https://oauth.net/2/
  4. Por que as chaves e segredos da API do OAuth não são seguros em aplicativos móveis https://developer.okta.com/blog/2019/01/22/oauth-api-keys-arent-safe-in-mobile-apps
  5. [RFC] OAuth 2.0 para aplicativos nativos https://tools.ietf.org/html/rfc8252
  6. [RFC] Chave de prova para troca de código por clientes públicos do OAuth https://tools.ietf.org/html/rfc7636
  7. [RFC] Modelo de ameaça do OAuth 2.0 e considerações de segurança https://tools.ietf.org/html/rfc6819
  8. [RFC] Protocolo de registro dinâmico de cliente OAuth 2.0 https://tools.ietf.org/html/rfc7591
  9. Google OAuth 2.0 para aplicativos para dispositivos móveis e computadores https://developers.google.com/identity/protocols/OAuth2InstalledApp

Créditos


Obrigado a todos que me ajudaram a escrever este artigo. Especialmente a Sergei Belov, Andrei Sumin, Andrey Labunets pelo feedback sobre detalhes técnicos, a Pavel Kruglov pela tradução em inglês e a Daria Yakovleva pela ajuda no lançamento da versão em russo deste artigo.

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


All Articles