Aprenda / Segurança web

FundamentosAula 8 de 1618 min0% da trilha

CSRF: quando o navegador da vítima ataca por ela

O atacante nunca vê a senha, nem o cookie — ele só precisa fazer o navegador da vítima disparar uma requisição por ele.

CSRF (Cross-Site Request Forgery) é um ataque estranho de entender na primeira vez, porque o atacante não rouba nada diretamente — ele engana o navegador da vítima pra disparar uma requisição autenticada em nome dela, aproveitando um comportamento que a lição 2 já mostrou: o navegador reenvia cookie automaticamente pra qualquer requisição pro domínio certo, não importa de onde essa requisição partiu.

O ataque, passo a passo

Navegador da vítima
site-malicioso.com
banco.com

Clique em “Reproduzir fluxo” para ver a requisição passo a passo.

o formulário escondido dentro de site-malicioso.com
<form action="https://banco.com/transferir" method="POST" id="f">
  <input type="hidden" name="valor" value="5000">
  <input type="hidden" name="destino" value="conta-do-atacante">
</form>
<script>document.getElementById("f").submit();</script>

Repare que site-malicioso.com nunca lê a resposta dessa requisição, nem precisa — ele só precisa que ela seja enviada com o cookie certo anexado. Isso já basta pra causar o efeito colateral (a transferência) do lado de banco.com, que processa a requisição achando que ela veio de um formulário legítimo do próprio site, porque o cookie de sessão confere perfeitamente.

Por que isso é um problema específico de autenticação por cookie

Esse ataque funciona porque o navegador reenvia cookie automaticamente, sem o atacante precisar fazer nada especial pra isso acontecer. Um bearer token (lição 4) não sofre desse problema do mesmo jeito: ele precisa ser anexado manualmente no header Authorization por código JavaScript — e site-malicioso.com não tem como ler o token guardado no localStorage de banco.com (isso violaria a mesma política de mesma origem que impede CORS não autorizado) nem forçar o navegador a inventar um header customizado numa submissão de formulário simples. Não é que bearer token seja "imune" a tudo — ele troca esse risco pela exposição a XSS/localStorage vista na lição 4 — mas especificamente contra CSRF, ele já nasce protegido pelo próprio mecanismo.

As defesas

A primeira linha de defesa já foi vista na lição 3: SameSite=Lax (ou Strict) no cookie de sessão já bloqueia a maior parte desse cenário, porque o navegador simplesmente não anexa o cookie numa requisição de POST disparada por outro site. A segunda camada, tradicionalmente usada antes de SameSite existir (e ainda recomendada como defesa adicional), é o token CSRF: um valor único, gerado pelo servidor e embutido no formulário legítimo, que precisa ser enviado de volta junto da requisição.

formulário legítimo, com token CSRF
<form action="/transferir" method="POST">
  <input type="hidden" name="csrf_token" value="f3a9c1e8...">
  <!-- site-malicioso.com não tem como saber esse valor, então não consegue reproduzi-lo -->
</form>

O servidor recusa qualquer requisição que não venha com o token CSRF correto e correspondente à sessão atual — e, como esse valor é gerado por requisição/sessão e não é previsível, o atacante em site-malicioso.com não tem como adivinhá-lo ou obtê-lo sem já ter acesso à página legítima.

Exercício

Uma API usa exclusivamente autenticação por bearer token (header Authorization, sem cookie nenhum envolvido). Um colega insiste em adicionar proteção CSRF mesmo assim, "por garantia". Ela é necessária nesse cenário? Justifique.

Quiz rápido

No ataque de CSRF descrito, o que exatamente site-malicioso.com precisa conseguir fazer pra ter sucesso?
Por que uma API autenticada só por bearer token (sem cookie) é naturalmente resistente a CSRF, mesmo sem nenhuma defesa adicional?