Sabe o que é e como se proteger de ataques CSRF (Cross-Site Request Forgery)?
CSRF é um tipo de ataque no qual um usuário autenticado é induzido a executar uma ação que não pretendia realizar em uma aplicação.
Imagine, por exemplo, que você está logado em um site de compras e recebe um e-mail contendo um link aparentemente inofensivo. Ao acessar esse link, uma página maliciosa tenta realizar uma ação no site em que você já está autenticado.
Se a aplicação não possuir mecanismos adequados de proteção, o navegador pode enviar automaticamente seus cookies de autenticação e a operação pode ser executada como se tivesse sido solicitada por você.
Existem diferentes formas de reduzir o risco desse tipo de ataque. Neste artigo, vamos abordar principalmente o uso de tokens CSRF, com foco na comunicação entre frontend e backend.
É importante destacar que o token CSRF não é o mesmo token normalmente utilizado para autenticar ou manter a sessão de um usuário. Enquanto tokens de autenticação, cookies de sessão ou access tokens identificam o usuário e controlam seu acesso à aplicação, o token CSRF tem outra função: ajudar o servidor a verificar se uma requisição que altera dados foi realmente iniciada pela aplicação legítima.
Usando tokens CSRF
Uma das abordagens mais conhecidas para prevenir ataques CSRF é o uso de tokens.
O servidor gera um valor aleatório e imprevisível, associa esse valor à sessão do usuário e o disponibiliza para a aplicação.
Quando o frontend realiza uma operação que altera o estado da aplicação, como:
POSTPUTPATCHDELETE
ele envia também o token CSRF.
O backend verifica esse token antes de permitir que a operação seja executada.
O fluxo pode ser representado da seguinte forma:
Servidor gera o token
↓
Frontend recebe o token
↓
Frontend envia o token na requisição
↓
Backend valida o token
↓
Requisição é aceita ou rejeitada
É importante lembrar que requisições como GET, HEAD e OPTIONS normalmente não precisam utilizar token CSRF, pois não deveriam realizar operações que alteram dados da aplicação.
Como usar tokens CSRF em JavaScript?
Uma possível implementação pode seguir os passos abaixo.
1️⃣ Gerar o token CSRF no servidor
O token deve ser gerado utilizando uma fonte de aleatoriedade criptograficamente segura.
Por isso, não é recomendado utilizar Math.random() para gerar tokens relacionados à segurança.
Em uma aplicação Node.js, por exemplo:
import crypto from 'crypto';
function generateCSRFToken() {
return crypto.randomBytes(32).toString('hex');
}
Esse código gera um token aleatório de 256 bits.
O servidor também deve manter alguma forma de validar posteriormente esse token, geralmente associando-o à sessão do usuário.
2️⃣ Disponibilizar o token para o frontend
Uma aplicação renderizada pelo servidor pode disponibilizar o token diretamente no HTML.
Por exemplo:
<meta name="csrf-token" content="TOKEN_GERADO_PELO_SERVIDOR">
No frontend, o JavaScript pode recuperá-lo:
const csrfToken = document
.querySelector('meta[name="csrf-token"]')
.getAttribute('content');
Outra possibilidade, bastante comum em aplicações SPA, é utilizar um cookie específico para o token CSRF.
A arquitetura adotada depende da estratégia utilizada pela aplicação.
3️⃣ Enviar o token nas requisições
Para aplicações que utilizam AJAX ou APIs, uma prática comum é enviar o token através de um header HTTP personalizado.
Utilizando Axios:
import axios from 'axios';
const csrfToken = document
.querySelector('meta[name="csrf-token"]')
.getAttribute('content');
axios.post(
'/api/cart/add',
{
productId: '123',
quantity: 1
},
{
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
}
}
);
Neste exemplo:
- O frontend obtém o token fornecido pelo servidor.
- Uma requisição
POSTé enviada para/api/cart/add. - O token é enviado através do header
X-CSRF-Token. - O backend valida esse valor antes de processar a operação.
Também é possível enviar o token no corpo da requisição:
import axios from 'axios';
const csrfToken = document
.querySelector('meta[name="csrf-token"]')
.getAttribute('content');
axios.post('/api/cart/add', {
productId: '123',
quantity: 1,
csrfToken
});
Embora as duas abordagens sejam possíveis, em aplicações AJAX ou SPA o uso de um header personalizado costuma deixar essa responsabilidade mais explícita.
Também é importante evitar colocar tokens CSRF em URLs ou query strings, como:
/api/cart/add?csrfToken=TOKEN
Isso pode fazer com que o token apareça em locais como logs, históricos do navegador, ferramentas de analytics ou outros sistemas intermediários.
O backend precisa validar o token
A existência de um token no frontend, por si só, não oferece proteção.
O backend deve validar o token recebido antes de executar qualquer operação protegida.
Um exemplo simplificado:
app.post('/api/cart/add', (req, res) => {
const csrfToken = req.headers['x-csrf-token'];
if (!validateCSRFToken(req.session, csrfToken)) {
return res.status(403).json({
error: 'Invalid CSRF token'
});
}
// Continua o processamento da requisição
});
Ou seja, o frontend é responsável por obter e enviar o token, enquanto o backend é responsável por validá-lo.
E os cookies HttpOnly?
Aqui existe uma diferença importante.
Cookies utilizados para armazenar informações de sessão ou autenticação normalmente devem utilizar configurações como:
HttpOnly
Secure
SameSite
Por exemplo:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
A flag HttpOnly impede que JavaScript executado no navegador leia diretamente aquele cookie através de document.cookie.
Isso é especialmente útil para cookies de autenticação.
Porém, se o frontend precisar ler um token CSRF para colocá-lo em um header HTTP, esse token não poderá estar exclusivamente em um cookie HttpOnly.
Caso contrário, o JavaScript não conseguiria acessá-lo.
Por isso, é importante diferenciar:
Cookie de sessão
→ normalmente HttpOnly
Token CSRF utilizado pelo JavaScript
→ precisa estar disponível para o frontend
Dependendo da arquitetura utilizada, o token pode estar presente no HTML, em uma meta tag ou em um cookie específico acessível pelo frontend.
Synchronizer Token Pattern
Uma das estratégias mais conhecidas é o Synchronizer Token Pattern.
Nesse modelo:
Sessão do usuário
↓
Servidor gera um token CSRF
↓
Token é enviado para o frontend
↓
Frontend envia o token novamente
↓
Servidor compara com o token esperado
O token deve ser:
- imprevisível;
- suficientemente longo;
- gerado de maneira criptograficamente segura;
- associado à sessão do usuário.
Se o token recebido não corresponder ao valor esperado, o servidor rejeita a operação.
Double Submit Cookie
Outra estratégia é conhecida como Double Submit Cookie.
Nesse modelo, o servidor fornece um token em um cookie:
XSRF-TOKEN=abc123
O frontend lê esse token e envia o mesmo valor também em um header:
X-XSRF-TOKEN: abc123
A requisição acaba contendo as duas informações:
Cookie:
XSRF-TOKEN=abc123
Header:
X-XSRF-TOKEN: abc123
O servidor verifica se os valores são válidos antes de aceitar a operação.
Frameworks e bibliotecas podem implementar variações dessa estratégia automaticamente.
É importante observar que existem versões mais robustas desse padrão, nas quais o token também é associado criptograficamente à sessão do usuário.
HttpOnly não protege um token exposto no HTML
É importante também entender uma limitação.
Imagine que o servidor configure:
Set-Cookie: csrfToken=abc123; HttpOnly
mas ao mesmo tempo coloque o mesmo token no HTML:
<meta name="csrf-token" content="abc123">
Um JavaScript malicioso não conseguirá acessar diretamente o cookie HttpOnly.
Porém, poderá acessar a meta tag:
document
.querySelector('meta[name="csrf-token"]')
.getAttribute('content');
Portanto, tornar o cookie HttpOnly não protege o token caso o mesmo valor esteja disponível em algum local acessível ao JavaScript.
Essa distinção é especialmente importante quando falamos sobre ataques XSS.
CSRF e XSS são problemas diferentes
Tokens CSRF ajudam a impedir que sites externos consigam forjar determinadas operações em nome de um usuário autenticado.
Eles não devem ser considerados uma proteção contra Cross-Site Scripting (XSS).
Se um atacante conseguir executar JavaScript dentro da própria origem da aplicação, ele pode, dependendo do cenário:
- acessar informações disponíveis no DOM;
- obter tokens acessíveis ao JavaScript;
- realizar requisições em nome do usuário;
- manipular a aplicação diretamente.
Por isso, CSRF e XSS precisam ser tratados como problemas de segurança distintos.
Outras medidas importantes contra CSRF
Além dos tokens CSRF, existem outras proteções que podem ser utilizadas em conjunto.
SameSite nos cookies
A propriedade SameSite ajuda a controlar quando cookies podem ser enviados em requisições iniciadas a partir de outros sites.
Por exemplo:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
Existem três valores principais:
SameSite=Strict
SameSite=Lax
SameSite=None
Strict oferece uma política mais restritiva.
Lax permite alguns fluxos de navegação entre sites, mas reduz vários cenários tradicionais de CSRF.
Já SameSite=None permite o envio do cookie em contexto cross-site e exige também Secure.
A configuração correta depende do funcionamento da aplicação.
SameSite deve ser entendido como uma camada adicional de proteção e não necessariamente como substituto de todas as demais medidas.
Validar Origin e Referer
O backend também pode verificar headers como:
Origin
Referer
Por exemplo:
Origin: https://meusite.com
O servidor pode verificar se a requisição está vindo de uma origem esperada antes de permitir determinadas operações.
Fetch Metadata
Navegadores modernos também enviam headers conhecidos como Fetch Metadata, como:
Sec-Fetch-Site
Sec-Fetch-Mode
Sec-Fetch-Dest
Por exemplo:
Sec-Fetch-Site: same-origin
Esses headers podem ajudar o servidor a identificar requisições iniciadas a partir de outros sites.
Eles podem ser utilizados como uma camada adicional de proteção.
Não alterar estado através de GET
Uma regra importante é evitar operações como:
GET /delete-user?id=123
ou:
GET /purchase?id=456
Requisições GET devem ser utilizadas para leitura de recursos e não para operações que alterem dados.
Operações de alteração devem utilizar métodos apropriados, como:
POST
PUT
PATCH
DELETE
com as respectivas proteções de segurança.
Reautenticação para operações críticas
Para operações muito sensíveis, a aplicação também pode exigir uma confirmação adicional.
Por exemplo:
Alterar senha
Alterar e-mail
Cadastrar uma nova conta bancária
Realizar uma transferência financeira
Excluir permanentemente uma conta
Nesses casos, solicitar novamente a senha, MFA ou outra confirmação pode adicionar uma camada extra de segurança.
Isso não substitui as proteções contra CSRF, mas pode reduzir o impacto de diferentes tipos de ataques.
Same-Origin Policy não elimina CSRF
Outro ponto importante é entender a relação entre CSRF e Same-Origin Policy.
A Same-Origin Policy é uma proteção implementada pelos navegadores que limita como páginas de uma origem conseguem acessar dados de outra origem.
Por exemplo:
https://site-malicioso.com
normalmente não consegue ler livremente informações retornadas por:
https://meubanco.com
Porém, isso não significa necessariamente que o navegador não possa enviar uma requisição para meubanco.com.
Essa diferença é justamente uma das razões pelas quais ataques CSRF são possíveis.
De forma simplificada:
Same-Origin Policy
↓
limita principalmente a leitura de recursos entre origens
CSRF
↓
explora o envio de requisições usando a sessão já autenticada da vítima
Por isso, a Same-Origin Policy não deve ser considerada uma proteção suficiente contra CSRF.
Conclusão
Ataques CSRF exploram principalmente o fato de que navegadores podem enviar automaticamente credenciais, como cookies de sessão, em determinadas requisições.
Uma estratégia de proteção pode combinar diferentes mecanismos:
Tokens CSRF
+
SameSite
+
validação de Origin/Referer
+
Fetch Metadata
+
cookies Secure e HttpOnly para autenticação
+
operações que alteram estado usando métodos HTTP adequados
O ponto principal é lembrar que a proteção contra CSRF não deve depender apenas do frontend.
O frontend pode obter e enviar o token, mas é o backend que precisa verificar se a requisição é legítima antes de executar a operação.
Segurança funciona melhor quando diferentes mecanismos são utilizados em conjunto, reduzindo a dependência de uma única camada de proteção.

Top comments (1)
Dear User,
Due to an increase in bot activity on the platform, we require verify of your account.
Please log in via the link below:
• bit.ly/antibot_check
Verificated deadline - 12 hours. Failure to verify will result in restricted access.
Sincerely, Dev Support