O que é CSRF e como evitar requisições forjadas
Entenda como ataques Cross-Site Request Forgery exploram a sessao autenticada do usuario e quais defesas realmente funcionam, de tokens a SameSite.

Você está logado no seu banco em uma aba. Em outra, abre um site qualquer que, sem você perceber, dispara uma requisição para o banco usando a sua sessão ativa. Se o banco aceitar, uma transferência pode acontecer sem que você tenha clicado em nada relevante. Esse é o mecanismo do CSRF (Cross-Site Request Forgery).
Neste artigo você vai entender por que o navegador colabora involuntariamente com esse ataque, em que situações ele funciona e quais defesas são eficazes de verdade. Spoiler: a combinação de tokens anti-CSRF e o atributo de cookie SameSite resolve a esmagadora maioria dos casos.
O que é CSRF
Cross-Site Request Forgery é um ataque em que um site malicioso induz o navegador da vítima a enviar uma requisição autenticada para outra aplicação na qual ela já está logada. O atacante não rouba credenciais nem lê respostas; ele apenas força uma ação aproveitando a sessão existente.
A chave para entender o CSRF é lembrar como os navegadores tratam cookies: por padrão, ao fazer uma requisição para um domínio, o navegador anexa automaticamente os cookies daquele domínio — inclusive o cookie de sessão. O servidor recebe a requisição, vê um cookie válido e assume que é o usuário legítimo agindo. O ataque explora exatamente essa confiança automática. O CSRF figura no contexto de falhas de controle de acesso do OWASP Top 10 explicado: as 10 maiores falhas de segurança web.
O que torna um app vulnerável
Para que um CSRF clássico funcione, três condições precisam estar presentes ao mesmo tempo:
- Autenticação por cookie automático: a aplicação identifica o usuário por um cookie que o navegador envia sozinho.
- Uma ação que muda estado: a requisição-alvo executa algo relevante (transferir, deletar, alterar dados).
- Parâmetros previsíveis: o atacante consegue montar a requisição sem precisar de nenhum valor secreto que ele não tenha como saber.
Quebrar qualquer uma dessas três condições neutraliza o ataque. As defesas que veremos atacam justamente os pontos 1 e 3.
Um exemplo concreto
Suponha que uma aplicação faça transferências por uma requisição como esta:
<form action="https://banco.com/transferir" method="POST">
<input name="destino" value="12345">
<input name="valor" value="1000">
</form>Um atacante hospeda uma página com um formulário idêntico que se envia sozinho assim que carrega:
<body onload="document.forms[0].submit()">
<form action="https://banco.com/transferir" method="POST">
<input type="hidden" name="destino" value="conta-do-atacante">
<input type="hidden" name="valor" value="5000">
</form>
</body>Se a vítima, logada no banco, visitar essa página, o navegador envia a requisição com o cookie de sessão anexado. Sem proteção, o banco processa a transferência como legítima. Repare que o atacante nunca viu a senha — ele apenas tomou carona na sessão.
CSRF nem sempre precisa de formulário
Vale entender que o vetor não se limita a formulários. Qualquer elemento que dispare uma requisição serve. Uma simples imagem pode acionar um GET com efeito colateral:
<img src="https://app.com/conta/deletar?id=42" width="0" height="0">Esse exemplo revela um anti-padrão importante: requisições GET jamais devem mudar estado. Operações que alteram dados precisam usar POST, PUT, PATCH ou DELETE, que são mais difíceis de forjar de forma silenciosa. Esse é um dos princípios básicos ao desenhar um O que é HTTP, seus métodos, status e como a web conversa: métodos seguros (como GET) devem ser apenas de leitura.
CSRF não é XSS
É comum confundir os dois, mas eles são diferentes:
- No XSS, o atacante executa script dentro do site da vítima e pode ler dados.
- No CSRF, o atacante não executa script no site alvo nem lê a resposta; ele apenas dispara uma ação às cegas.
Por isso o CSRF afeta principalmente operações que mudam estado (transferir, deletar, alterar e-mail), e não simples leituras. Ainda assim, os dois se relacionam: um XSS pode contornar defesas anti-CSRF, então a proteção contra o forjamento depende também de não ter scripts injetados — assunto de O que é XSS (Cross-Site Scripting)?.
Um ponto importante: se o site tem XSS, nenhuma defesa anti-CSRF segura. Um script injetado roda na origem do alvo, pode ler o token e montar a requisição legítima. Por isso, mitigar XSS é pré-requisito para que a proteção CSRF tenha valor.
Defesa 1: tokens anti-CSRF
A defesa clássica é o token anti-CSRF (também chamado de synchronizer token). A ideia:
- Ao renderizar um formulário, o servidor gera um token aleatório e imprevisível, ligado à sessão do usuário.
- Esse token é embutido no formulário, em um campo oculto.
- Ao receber a requisição, o servidor valida se o token enviado corresponde ao esperado.
<form action="/transferir" method="POST">
<input type="hidden" name="csrf_token" value="a1b2c3d4-e5f6-...">
<!-- demais campos -->
</form>Por que isso funciona? O site malicioso não tem como adivinhar o token, porque não consegue ler o conteúdo das páginas do domínio alvo (a política de mesma origem impede). Sem o token correto, a requisição forjada é rejeitada. O OWASP Web Security Testing Guide detalha como verificar a presença e a robustez desses tokens (OWASP Foundation, 2020).
O padrão Double Submit Cookie
Manter o token associado à sessão no servidor exige guardar estado. Uma alternativa sem estado é o double submit cookie: o servidor envia o token tanto em um cookie quanto espera recebê-lo em um cabeçalho ou campo de formulário. Como o site atacante não consegue ler o cookie do domínio alvo (graças à política de mesma origem), ele não consegue replicar o valor no cabeçalho. O servidor só aceita se os dois baterem.
POST /transferir HTTP/1.1
Cookie: csrf=a1b2c3d4
X-CSRF-Token: a1b2c3d4Esse padrão é popular em APIs e SPAs porque não exige armazenar o token no servidor. Sua robustez, porém, depende de subdomínios confiáveis — por isso costuma-se assinar o token para evitar adulteração.
Cuidados ao implementar tokens
- O token deve ser gerado com aleatoriedade criptograficamente segura, não com algo previsível.
- Deve ser validado em toda requisição que muda estado, sem exceções esquecidas.
- A comparação deve ser de tempo constante, para não vazar informação.
- Não exponha o token em URLs (elas vazam por logs, histórico e cabeçalho Referer).
Defesa 2: cookies SameSite
O atributo SameSite instrui o navegador sobre quando enviar um cookie em requisições entre sites. Ele ataca a raiz do problema — o envio automático do cookie de sessão:
- SameSite=Strict: o cookie nunca é enviado em requisições originadas de outro site. Máxima proteção, mas pode atrapalhar fluxos legítimos (como chegar de um link externo já logado).
- SameSite=Lax: o cookie é enviado em navegações de nível superior (clicar em um link), mas não em requisições cruzadas que mudam estado, como POST de outro site. É um bom equilíbrio e hoje é o padrão na maioria dos navegadores.
- SameSite=None: envia o cookie em qualquer contexto (exige Secure); use apenas quando realmente necessário.
Set-Cookie: sessao=abc123; HttpOnly; Secure; SameSite=LaxCom SameSite=Lax ou Strict, o cenário do banco descrito acima já falha, porque o cookie de sessão não acompanha o POST cruzado.
SameSite não é uma bala de prata
Apesar de poderoso, o SameSite tem limitações que justificam não depender só dele:
- Comportamento entre navegadores varia: versões antigas podem não respeitar o padrão, e o Lax padrão tem nuances de timing.
- Não protege ataques same-site: se o atacante controla um subdomínio do mesmo site (em alguns cenários), o cookie ainda pode viajar.
- Lax ainda permite GET cruzado: por isso a regra de nunca mudar estado em GET continua valendo.
A recomendação é tratar SameSite como uma camada de defesa robusta, mas combiná-lo com tokens — defesa em profundidade.
Defesa em profundidade: combine as camadas
Nenhuma defesa isolada é perfeita, então o recomendado é somar proteções:
- Tokens anti-CSRF para validar a origem legítima da requisição.
- SameSite para barrar o envio automático do cookie.
- Verificar cabeçalhos Origin/Referer em requisições sensíveis, rejeitando origens inesperadas.
- Exigir reautenticação em ações críticas (como mudar senha), reduzindo o valor de uma sessão sequestrada.
É importante distinguir o que cada peça protege: o token e o SameSite cuidam do forjamento, mas quem o usuário é e o que ele pode fazer depende de um controle de acesso correto — tema de Autenticação vs autorização: qual a diferença?.
Verificação de Origin: simples e eficaz
A checagem do cabeçalho Origin (e, na ausência dele, Referer) é uma defesa subestimada. Em uma requisição que muda estado, o servidor compara a origem declarada com a sua própria:
Origin recebido: https://site-malicioso.com
Origin esperado: https://app.com
=> rejeitarDiferente do cookie, o cabeçalho Origin é controlado pelo navegador e não pode ser forjado por scripts de outro site. É uma checagem barata que reforça as demais.
Casos especiais que enganam
Alguns cenários parecem seguros mas escondem armadilhas de CSRF:
- Login CSRF: o atacante força a vítima a fazer login na conta dele. A vítima, sem perceber, passa a usar a conta do atacante e alimenta-a com seus dados (histórico, cartões, buscas). A defesa é proteger também o formulário de login com token CSRF.
- JSON com Content-Type simples: muita gente acha que enviar JSON protege, mas um formulário pode forjar requisições com Content-Type: text/plain contendo um corpo que o servidor interpreta como JSON. Não confie no tipo de conteúdo como única barreira.
- Endpoints de "logout": forçar o logout da vítima parece inofensivo, mas pode ser usado em ataques encadeados (deslogar para depois induzir um novo login controlado). Vale proteger.
- Métodos sobrescritos: frameworks que aceitam _method=DELETE em um POST reabrem o vetor de formulário. Garanta que o token seja exigido independentemente do método efetivo.
A lição geral: qualquer endpoint que produz efeito colateral é candidato a CSRF, mesmo os que parecem secundários.
A política de mesma origem, a base de tudo
Quase todas as defesas de CSRF se apoiam, no fundo, na política de mesma origem (same-origin policy) do navegador. Ela define que scripts de uma origem (esquema + host + porta) não podem ler dados de outra origem. É por isso que:
- O site atacante não consegue ler o token CSRF embutido na página do alvo.
- O site atacante não consegue ler a resposta da requisição forjada.
Note a assimetria crucial: a política impede ler, mas não impede enviar. Um formulário pode disparar um POST para qualquer origem; o que ele não pode é ver o que voltou. Entender essa fronteira explica por que o CSRF existe (o envio é permitido) e por que os tokens funcionam (a leitura é bloqueada). Essa mesma fronteira está no coração de outros temas de segurança web, e revisitá-la ajuda a raciocinar sobre o O que é XSS (Cross-Site Scripting)?, que justamente quebra a política ao injetar script dentro da origem-alvo.
CSRF em APIs e tokens
Em arquiteturas modernas baseadas em APIs, o cenário muda. Quando a autenticação usa um token enviado manualmente em um cabeçalho (por exemplo, Authorization: Bearer ...) em vez de um cookie automático, o CSRF clássico deixa de funcionar, porque o navegador não anexa esse cabeçalho sozinho em requisições cruzadas. Por isso, entender os mecanismos de O que é JWT (JSON Web Token)? ajuda a decidir o modelo de sessão. Ainda assim, APIs que usam cookies para sessão continuam vulneráveis e precisam das defesas acima — detalhamos o tema em Segurança de APIs: protegendo seus endpoints.
CORS não te protege de CSRF
Um equívoco perigoso e frequente: achar que ter CORS configurado defende contra CSRF. Não defende. O CORS controla se um script de outra origem pode ler a resposta de uma requisição cruzada — ele não impede que a requisição seja enviada nem que o servidor a processe. Um formulário autoenviável ou uma imagem dispara a requisição independentemente de CORS, e o efeito colateral acontece no servidor antes de qualquer checagem de leitura. CORS e CSRF resolvem problemas diferentes; não confunda um pelo outro.
Cookies modernos: a abordagem "__Host-"
Vale conhecer um detalhe que reforça a proteção de cookies de sessão: o prefixo __Host-. Um cookie nomeado com esse prefixo só é aceito pelo navegador se atender a condições estritas — Secure, sem atributo Domain (preso ao host exato) e com Path=/. Isso impede que um subdomínio comprometido sobrescreva o cookie de sessão (um ataque chamado cookie tossing), endurecendo o cenário same-site que discutimos.
Set-Cookie: __Host-sessao=abc123; Secure; HttpOnly; SameSite=Lax; Path=/Combinado com HttpOnly (que impede leitura por JavaScript e ajuda contra XSS), você obtém um cookie de sessão difícil de manipular tanto por CSRF quanto por scripts injetados.
Como testar se você está protegido
Validar a defesa é tão importante quanto implementá-la. Um roteiro prático de verificação:
- Tente reproduzir o ataque: monte uma página de teste em outra origem com um formulário autoenviável apontando para um endpoint que muda estado. Sem proteção, a ação acontece.
- Remova o token e reenvie: uma requisição sem o token CSRF, ou com um token inválido, deve ser rejeitada com erro (tipicamente 403).
- Reutilize o token de outro usuário: o token de um usuário não pode ser válido para a sessão de outro.
- Inspecione o cookie de sessão: confirme SameSite, Secure e HttpOnly no DevTools.
- Forje o Origin: se você verifica origem, requisições com Origin inesperado devem cair.
Ferramentas de teste de segurança automatizam boa parte disso, mas entender o que cada checagem prova evita falsa sensação de segurança.
Erros comuns na proteção contra CSRF
- Proteger apenas alguns endpoints: basta um endpoint de mudança de estado desprotegido para abrir a brecha.
- Mudar estado com GET: facilita ataques via
, e prefetch.
- Confiar só em Referer: ele pode estar ausente por políticas de privacidade; use-o como reforço, não como única barreira.
- Colocar o token em URL: vaza por logs e histórico.
- Esquecer que XSS anula tudo: sem mitigar XSS, qualquer token pode ser lido e reutilizado.
Perguntas frequentes
Preciso de token CSRF se já uso SameSite=Strict? Para muitos apps, SameSite cobre o caso comum, mas a recomendação de segurança é manter as duas camadas, dada a variação entre navegadores e cenários same-site.
APIs com Authorization: Bearer precisam de proteção CSRF? Se a autenticação não depende de cookie automático, o CSRF clássico não se aplica. O risco volta se você usar cookies para a sessão.
CSRF pode roubar meus dados? Não diretamente. O atacante não lê a resposta; ele força ações. O dano é por efeito colateral (transferências, alterações), não por vazamento de leitura.
Token CSRF protege contra XSS? Não. São ataques distintos. E pior: um XSS bem-sucedido derrota a proteção CSRF. Trate as duas defesas como complementares.
Conclusão
O CSRF é engenhoso porque não quebra nada do lado do servidor: ele abusa de um comportamento legítimo do navegador, o envio automático de cookies. A boa notícia é que as defesas são bem estabelecidas. Use tokens anti-CSRF em operações que mudam estado, configure cookies de sessão com SameSite=Lax ou Strict, jamais altere estado com GET e considere a verificação de origem em ações críticas. Para fluxos baseados em tokens de cabeçalho, o risco quase desaparece. Aplicando essas camadas, você fecha uma das brechas mais silenciosas e exploradas da web.
Referências
- OWASP Foundation (2021). OWASP Top 10:2021. OWASP.
- OWASP Foundation (2020). OWASP Web Security Testing Guide v4.2. OWASP.
- OWASP Foundation (2021). Cross-Site Request Forgery Prevention Cheat Sheet. OWASP.
- West, M., Goodwin, M. (2016). Same-site Cookies (draft-ietf-httpbis-cookie-same-site). IETF.


