Proteções contra ataques comuns em autenticação e autorização (CSRF, XSS, brute force)

Capítulo 9

Tempo estimado de leitura: 12 minutos

+ Exercício

CSRF (Cross-Site Request Forgery): como acontece e por que é perigoso

CSRF ocorre quando um atacante faz o navegador da vítima enviar uma requisição autenticada para sua aplicação sem que a vítima perceba. Isso é possível porque, em muitos cenários, o navegador anexa automaticamente credenciais em requisições (principalmente cookies). Se a aplicação confiar apenas no fato de “o cookie veio junto”, ela pode executar ações sensíveis (ex.: trocar e-mail, alterar senha, transferir saldo) disparadas por uma página maliciosa.

Fluxo típico de ataque

  • A vítima está logada no https://app.exemplo.com (cookie de sessão válido).
  • Ela visita https://site-malicioso.com.
  • O site malicioso dispara uma requisição para https://app.exemplo.com/conta/email (por <form> auto-submit, <img>, fetch etc.).
  • O navegador envia o cookie junto (dependendo de políticas como SameSite e do tipo de requisição).
  • Se o servidor não exigir uma prova adicional de intenção, a ação é executada.

Mitigações de CSRF

1) SameSite em cookies (primeira linha de defesa)

SameSite controla quando o navegador envia cookies em contextos cross-site. É uma mitigação importante, mas não deve ser a única em operações críticas.

  • SameSite=Strict: cookie só é enviado em navegação “same-site”. Mais seguro, mas pode quebrar fluxos (ex.: login via redirecionamento, links vindos de outros sites).
  • SameSite=Lax: cookie é enviado em navegação top-level (ex.: clicar em link) e em alguns GETs, mas não em POSTs típicos de formulários cross-site. Bom padrão para muitos casos.
  • SameSite=None; Secure: cookie é enviado cross-site (necessário para alguns cenários como iframes/SSO), mas exige HTTPS. Nesse caso, proteção anti-CSRF vira obrigatória.

Exemplo de configuração de cookie (conceitual):

Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax

Observação prática: SameSite reduz muito CSRF clássico via POST cross-site, mas não substitui token anti-CSRF em aplicações que precisam de SameSite=None ou que tenham endpoints sensíveis expostos a navegação cross-site.

2) Anti-CSRF token (sincronizador): passo a passo

Ideia: além do cookie, o cliente precisa enviar um token imprevisível que o atacante não consegue ler (por causa da política de mesma origem). O servidor valida esse token antes de executar a ação.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Passo a passo (padrão sincronizador):

  • Ao renderizar a página (ou ao fornecer um endpoint para obter token), o servidor gera um token e o associa à sessão do usuário.
  • O token é inserido em formulários ou enviado em um header customizado em requisições AJAX.
  • Em cada requisição mutável (POST/PUT/PATCH/DELETE), o servidor verifica se o token enviado corresponde ao token esperado para aquela sessão.
  • Se faltar ou não bater: rejeitar com 403 Forbidden.

Exemplo (formulário):

<form method="POST" action="/conta/email">  <input type="hidden" name="csrf_token" value="...">  <input type="email" name="email">  <button>Salvar</button></form>

Exemplo (AJAX com header):

fetch('/conta/email', {  method: 'POST',  headers: {    'Content-Type': 'application/json',    'X-CSRF-Token': csrfToken  },  body: JSON.stringify({ email })});

3) Double Submit Cookie: passo a passo

Ideia: o servidor emite um cookie com um valor aleatório (não HttpOnly, para que o front-end consiga ler) e o cliente envia o mesmo valor em um header ou campo. O servidor compara cookie vs header/campo. O atacante consegue forçar o envio do cookie, mas não consegue ler o valor para replicar no header/campo.

Passo a passo:

  • Servidor define um cookie csrf com valor aleatório.
  • Front-end lê o cookie csrf e envia o valor em X-CSRF-Token (ou campo oculto).
  • Servidor valida se Cookie[csrf] == Header[X-CSRF-Token].

Exemplo (conceitual):

Set-Cookie: csrf=RANDOM; Secure; SameSite=Lax
// cliente lê document.cookie e envia X-CSRF-Token: RANDOM

Cuidados: se houver XSS, o atacante pode ler esse cookie e burlar o esquema. Por isso, double submit cookie é uma mitigação contra CSRF, não contra XSS.

4) Verificação de Origin/Referer (quando aplicável)

Para requisições mutáveis, o servidor pode validar o header Origin (preferível quando presente) e, como fallback, Referer. Se a origem não for a esperada, rejeitar.

  • Quando funciona bem: APIs e back-ends que recebem requisições de browsers modernos, especialmente em POST/PUT/DELETE.
  • Limitações: alguns ambientes removem/alteram Referer; Origin pode não existir em certos fluxos; não substitui token em cenários complexos.

Checklist de validação:

  • Aplicar em métodos mutáveis.
  • Permitir apenas origens conhecidas (lista explícita).
  • Falhar fechado (se header esperado não existir, decidir política: exigir token ou bloquear).

XSS (Cross-Site Scripting): como rouba tokens e sessões

XSS acontece quando a aplicação permite que conteúdo controlado por usuário seja interpretado como código no navegador (geralmente JavaScript). Com XSS, o atacante passa a executar scripts no contexto do seu domínio, podendo:

  • Roubar dados acessíveis via JavaScript (ex.: tokens armazenados em localStorage, dados exibidos na página).
  • Realizar ações em nome do usuário (mesmo que cookies sejam HttpOnly), disparando requisições autenticadas a partir da própria página comprometida.
  • Capturar informações sensíveis digitadas (ex.: senha em um formulário falso).

Exemplo conceitual de XSS refletido

Um endpoint imprime um parâmetro sem escapar:

// anti-exemplo conceitual: renderiza ?q= diretamente no HTML<div>Resultados para: {q}</div>

Se q for <script>...</script>, o navegador executa o script.

Mitigações de XSS

1) Escaping/encoding na saída (regra base)

O princípio é: dados não são código. Ao inserir dados em HTML, atributos, JavaScript inline ou URLs, aplicar o encoding correto para aquele contexto.

  • Contexto HTML: escapar < > & " '.
  • Contexto atributo: além de escapar, evitar concatenar atributos perigosos (ex.: onerror).
  • Contexto JS: evitar interpolar strings em scripts; preferir dados via JSON seguro e APIs do DOM.

Prática recomendada: usar templates/frameworks que façam escaping por padrão e revisar pontos onde o escaping é desativado.

2) Sanitização (quando você precisa aceitar HTML)

Se o produto exige que usuários publiquem conteúdo com HTML (ex.: comentários com formatação), use sanitização com allowlist: permitir apenas tags e atributos seguros, removendo scripts, handlers e URLs perigosas.

  • Preferir allowlist (permitir poucos) em vez de blocklist (tentar bloquear muitos).
  • Sanitizar no servidor (fonte de verdade) e, se necessário, também no cliente para UX.

3) CSP (Content Security Policy) para reduzir impacto

CSP ajuda a bloquear execução de scripts injetados e reduzir vetores comuns (inline scripts, fontes externas não autorizadas). Uma política bem configurada pode impedir que um XSS “funcione” mesmo que a injeção aconteça.

Exemplo conceitual de cabeçalho (ajuste conforme seu app):

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

Pontos práticos:

  • Evitar 'unsafe-inline' em script-src.
  • Se precisar de inline, preferir nonces/hashes.
  • Usar frame-ancestors para mitigar clickjacking (relacionado a abuso de sessão).

4) Redução da superfície de dados sensíveis

Mesmo com defesas, trate XSS como risco residual e minimize o que um script conseguiria exfiltrar:

  • Evitar expor tokens em JavaScript quando possível.
  • Não retornar dados sensíveis desnecessários em respostas (ex.: PII, segredos, claims excessivos).
  • Cookies de sessão com HttpOnly reduzem roubo direto por JS, mas não impedem ações maliciosas via XSS.

Brute force e credential stuffing: diferenças e ameaças

  • Brute force: tentativa repetida de adivinhar senha (muitas combinações) para um usuário.
  • Credential stuffing: uso de credenciais vazadas (email/senha) em massa, explorando reutilização de senha. Aqui, a taxa de acerto pode ser alta mesmo com poucas tentativas por conta.

O objetivo das proteções é reduzir tentativas automatizadas, aumentar custo do ataque e detectar padrões anômalos sem bloquear usuários legítimos.

Mitigações para brute force/credential stuffing

1) Rate limiting (por IP, por conta e por rota)

Aplicar limites em endpoints sensíveis (login, reset de senha, verificação de OTP). Combine dimensões:

  • Por IP: limita ataques concentrados.
  • Por conta (identificador): limita ataques distribuídos contra um usuário específico.
  • Por ASN/país (quando fizer sentido): detectar infra de bot/hosting.

Exemplo de política (conceitual):

DimensãoLimiteAção
Por IP30 tentativas / 5 min429 + backoff
Por conta10 tentativas / 15 mindesafio adicional / bloqueio temporário
Por IP+conta5 tentativas / 5 minbloqueio curto

2) Backoff progressivo (atraso incremental)

Em vez de apenas bloquear, aumente o tempo de resposta ou imponha espera crescente após falhas consecutivas. Isso reduz eficiência de automação e diminui impacto em usuários que erram poucas vezes.

Passo a passo:

  • Contar falhas recentes por conta e/ou IP.
  • Aplicar atraso: 0s, 1s, 2s, 4s, 8s… com teto.
  • Resetar contador após login bem-sucedido ou após janela de tempo.

3) Lockout inteligente (evitar DoS contra usuários)

Bloquear uma conta por muitas tentativas pode virar arma para o atacante (negação de serviço). Prefira lockout “inteligente”:

  • Bloqueio temporário curto e escalonado.
  • Bloqueio condicionado a sinais adicionais (IP suspeito, ASN de datacenter, ausência de cookies de dispositivo, alta taxa).
  • Permitir recuperação segura (ex.: desafio adicional) em vez de bloqueio longo.

4) Detecção por IP/ASN, reputação e sinais de automação

Credential stuffing costuma vir de infra distribuída. Sinais úteis:

  • ASN de provedores de cloud/hosting com histórico de abuso.
  • Muitos logins para contas diferentes a partir do mesmo IP/ASN.
  • Headers e fingerprints inconsistentes (ex.: user-agent rotativo, ausência de sinais de navegador real).
  • Taxa de erro elevada e padrões de tentativa (listas).

Ação típica: exigir desafio adicional, reduzir limites, ou bloquear por janela curta.

5) Listas de senha vazada e políticas de senha orientadas a risco

Para reduzir sucesso de credential stuffing:

  • Na criação/troca de senha, verificar se a senha está em listas de senhas vazadas/mais comuns.
  • Bloquear senhas fracas e reutilizadas em vazamentos conhecidos.
  • Combinar com alertas de login suspeito e recomendações de troca.

6) Alertas e telemetria de segurança

Sem visibilidade, você só descobre o ataque quando o dano já ocorreu. Instrumente:

  • Eventos: falha de login, sucesso, reset de senha, mudança de email, mudança de 2FA.
  • Alertas: picos de falha por rota, por IP/ASN, por conta.
  • Notificações ao usuário: novo dispositivo/localização, múltiplas falhas, troca de credenciais.

Laboratório conceitual: qual proteção aplicar em diferentes arquiteturas

Objetivo: dado um cenário de autenticação, identificar quais ataques são mais prováveis e quais proteções são obrigatórias vs recomendadas.

Cenário A: Sessão com cookie (browser tradicional)

Arquitetura: o navegador autentica via cookie de sessão enviado automaticamente.

  • CSRF: risco alto. Aplicar SameSite (Lax/Strict quando possível) + anti-CSRF token (ou double submit) em rotas mutáveis. Considerar validação de Origin.
  • XSS: risco alto. Aplicar escaping/encoding, sanitização onde houver HTML do usuário, CSP. Cookies HttpOnly ajudam contra roubo direto de sessão, mas não impedem ações via XSS.
  • Brute force/stuffing: rate limiting por IP/conta, backoff, lockout inteligente, detecção por ASN, listas de senha vazada, alertas.

Cenário B: JWT em cookie (SPA + API, token enviado automaticamente)

Arquitetura: o JWT fica em cookie e é enviado automaticamente em requisições.

  • CSRF: risco alto (mesma lógica do cookie de sessão). Aplicar SameSite + anti-CSRF token/double submit + validação de Origin em mutações.
  • XSS: ainda crítico. Se o cookie for HttpOnly, reduz roubo do JWT via JS, mas XSS ainda pode executar ações autenticadas. CSP e escaping continuam essenciais.
  • Brute force/stuffing: mesmas medidas do cenário A.

Cenário C: JWT em header Authorization (token não é enviado automaticamente)

Arquitetura: o front-end adiciona Authorization: Bearer ... manualmente.

  • CSRF: em geral, risco menor para endpoints que exigem header Authorization, porque um site atacante não consegue forçar o navegador a anexar esse header em uma requisição cross-site comum. Ainda assim, se houver endpoints que aceitam cookie ou outras credenciais automáticas, eles continuam sujeitos a CSRF.
  • XSS: risco muito alto se o token for acessível ao JavaScript (ex.: armazenado em memória/armazenamento web). Um XSS pode exfiltrar o token e reutilizá-lo fora do navegador. Mitigações: escaping/encoding, CSP forte, sanitização e reduzir exposição de dados; evitar persistir token em locais facilmente acessíveis quando possível.
  • Brute force/stuffing: mesmas medidas do cenário A, com atenção extra a endpoints de emissão/refresh de token.

Exercício guiado (checklist de decisão)

Para cada endpoint mutável (ex.: /transferencias, /conta/email):

  • Ele aceita autenticação via cookie enviado automaticamente? Se sim: aplicar proteção anti-CSRF (SameSite + token e/ou Origin).
  • Ele pode ser acionado por navegação cross-site (form/image/link)? Se sim: reforçar validação (método, content-type, Origin) e exigir token anti-CSRF.
  • O front-end renderiza dados do usuário? Se sim: garantir escaping por padrão e sanitização quando HTML for permitido.
  • O endpoint é alvo de tentativa automatizada (login/reset/OTP)? Se sim: rate limiting + backoff + detecção + alertas.

Tabela-resumo: ameaças x arquitetura

ArquiteturaCSRFXSSBrute force / stuffing
Sessão em cookieAlto (mitigar com SameSite + token + Origin)Alto (escaping, CSP, sanitização)Alto (rate limit, backoff, lockout inteligente, detecção)
JWT em cookieAlto (mesmas defesas de cookie)Alto (HttpOnly ajuda contra roubo, não contra ações)Alto (principalmente emissão/refresh)
JWT em headerMenor (se somente header), mas cuidado com endpoints que aceitam cookieMuito alto se token acessível ao JS (roubo/exfiltração)Alto (proteger endpoints de autenticação)

Agora responda o exercício sobre o conteúdo:

Em uma aplicação que autentica usuários por cookie enviado automaticamente pelo navegador, qual combinação de medidas é mais adequada para reduzir risco de CSRF em rotas mutáveis?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Como o navegador anexa cookies automaticamente, é preciso reduzir o envio cross-site (SameSite) e exigir uma verificação extra (token anti-CSRF ou double submit). Validar Origin/Referer pode complementar, mas não substitui tokens em cenários críticos.

Próximo capitúlo

Políticas de senha e recuperação de conta no back-end

Arrow Right Icon
Capa do Ebook gratuito Autenticação e Autorização no Back-end: Sessões, JWT e Boas Práticas
50%

Autenticação e Autorização no Back-end: Sessões, JWT e Boas Práticas

Novo curso

18 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.