
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:
- 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.
- 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.2O protocolo OAuth 2.0 pode ser dividido em três etapas principais:
- [etapas AC] Receba um
code
authorization_code
(daqui em diante, code
).
- [etapas DE] Troca de
code
para access_token
.
- Obtenha recursos via
access_token
.
Vamos elaborar o processo de obtenção
code
valor do
code
:
- [Etapa A] O cliente redireciona o usuário para o provedor de serviços.
- [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).
- [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
:
- [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.
- [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.1O esquema principal é dividido nas mesmas etapas principais:
- [etapas 1 a 4 na imagem] Obtenha
code
. - [etapas 5 a 6 da figura] Troque
code
para access_token
- 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:
- Todo cliente de serviço deve passar pelo procedimento de verificação .
- Os usuários do Android podem desativar o AppLink para um aplicativo específico nas configurações.
- 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-1Aqui 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.1A 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:
- O cliente gera o
code_verifier
e o memoriza.
- O cliente escolhe
code_challenge_method
e recebe code_challenge
do code_verifier
.
- [Etapa A] O cliente solicita
code
, com code_challenge
e code_challenge_method
adicionados à solicitação.
- [Etapa B] O provedor armazena
code_challenge
e code_challenge_method
no servidor e retorna o code
para um cliente.
- [Etapa C] O cliente solicita o
access_token
, com o code_verifier
adicionado a ele.
- O provedor recebe
code_challenge
do code_challenge
recebido e o compara ao code_challenge
que ele salvou.
- [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.
- Primeiro, o
code
solicitações legítimas de aplicativos ( code_challenge
e code_challenge_method
são enviados junto com a solicitação ).
- O aplicativo malicioso intercepta o
code
(mas não o code_challenge
, pois o código _challenge
não está na resposta).
- Aplicativo malicioso solicita
access_token
(com code
válido, mas sem code_verifier
válido).
- 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:
- O aplicativo cliente gera e salva o token CSRF no dispositivo móvel de um cliente.
- O aplicativo cliente inclui o token CSRF na solicitação de acesso ao
code
.
- O servidor retorna o mesmo token CSRF com o
code
em sua resposta.
- 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:
- O usuário digita seu login e senha para a conta do provedor de serviços no aplicativo, que pode facilmente roubar esses dados.
- 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.1A 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:
- 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.
- 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:
- 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 ?
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.
Client_secret
é inútil , a menos que seja armazenado no back-end. Não o entregue aos clientes públicos.
- Não use o WebView para obter a tela de consentimento; use a guia personalizada do navegador.
- Para se defender contra ataques de interceptação de código, use
code_challenge
.
- Para se defender do OAuth 2.0 CSRF, use
state
.
- 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).
- 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.
Code
deve ser usado apenas uma vez, com uma vida útil curta.
- 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.
- 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.
- 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
- "Vulnerabilidades do OAuth 2.0 para dispositivos móveis" https://www.youtube.com/watch?v=vjCF_O6aZIg
- Pesquisa de condição de corrida do OAuth 2.0 https://hackerone.com/reports/55140
- Quase tudo sobre o OAuth 2.0 em um só lugar https://oauth.net/2/
- 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
- [RFC] OAuth 2.0 para aplicativos nativos https://tools.ietf.org/html/rfc8252
- [RFC] Chave de prova para troca de código por clientes públicos do OAuth https://tools.ietf.org/html/rfc7636
- [RFC] Modelo de ameaça do OAuth 2.0 e considerações de segurança https://tools.ietf.org/html/rfc6819
- [RFC] Protocolo de registro dinâmico de cliente OAuth 2.0 https://tools.ietf.org/html/rfc7591
- 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.