CSRF e CORS: Protegendo Requisições do Navegador Corretamente
Você construiu uma aplicação web com uma API limpa, mas então percebe requisições estranhas nos seus logs—ou pior, um scanner de segurança sinaliza seu site por configurações incorretas de CSRF e CORS. Essas duas siglas frequentemente são agrupadas, mas resolvem problemas diferentes. Entendê-las mal pode deixar seus usuários vulneráveis ou quebrar requisições cross-origin legítimas.
Neste artigo, vamos esclarecer o que CSRF e CORS realmente são, como eles interagem com a segurança do navegador e fornecer passos concretos para proteger suas aplicações sem quebrar funcionalidades.
O que é CSRF e por que você deve se importar?
Cross-Site Request Forgery (CSRF) é um ataque que engana o navegador do usuário para enviar uma requisição a um site onde ele está autenticado. Imagine que você está logado no seu banco em bank.com. Você então visita um site malicioso que contém uma tag de imagem como <img src="https://bank.com/transfer?to=attacker&amount=1000">. Seu navegador inclui automaticamente seus cookies do banco na requisição, e se o banco não tiver proteções contra CSRF, a transferência é realizada.
O ponto principal: CSRF explora a confiança que um site tem no navegador do usuário. O atacante não precisa roubar sua sessão; ele só precisa que seu navegador faça uma requisição em seu nome.
Como funcionam os ataques CSRF
Para um ataque CSRF ter sucesso, três condições devem ser atendidas:
- A vítima deve estar autenticada (por exemplo, ter um cookie de sessão válido).
- O atacante deve conhecer a estrutura da requisição (endpoint, parâmetros).
- A requisição não deve incluir parâmetros imprevisíveis que o atacante não consiga adivinhar.
Alvos comuns são operações que alteram estado: mudar e-mail, transferir fundos, publicar conteúdo ou modificar permissões.
O que é CORS e por que ele existe?
Cross-Origin Resource Sharing (CORS) é um mecanismo do navegador que permite ou nega que páginas web façam requisições a um domínio diferente daquele que serviu a página. É uma extensão da Política de Mesma Origem (SOP), que restringe como um documento ou script carregado de uma origem pode interagir com recursos de outra origem.
Sem CORS, um site malicioso poderia usar JavaScript para ler dados da API do seu banco se você estiver logado. CORS dá aos servidores uma forma de permitir explicitamente certas requisições cross-origin.
A Política de Mesma Origem (SOP)
Duas URLs têm a mesma origem se o protocolo, host e porta forem idênticos. Por exemplo, https://example.com/app e https://example.com/api compartilham a mesma origem, mas http://example.com (protocolo diferente) e https://api.example.com (host diferente) não.
A SOP impede que scripts de uma origem leiam respostas de outra origem. O CORS flexibiliza isso adicionando cabeçalhos HTTP que dizem ao navegador se deve permitir a requisição.
CSRF vs CORS: Principais diferenças
É crucial entender que CSRF e CORS não são opostos; eles abordam preocupações de segurança diferentes. CSRF trata de prevenir requisições não autorizadas que alteram estado, enquanto CORS trata de controlar quais origens podem ler respostas.
| Aspecto | CSRF | CORS |
|---|---|---|
| Objetivo principal | Prevenir requisições forjadas | Controlar leituras cross-origin |
| Vetor de ataque | Site malicioso dispara requisições | Site malicioso lê respostas |
| Mecanismo de defesa | Tokens, cookies SameSite | Cabeçalhos HTTP (Access-Control-*) |
| Aplicação pelo navegador | Nenhuma (servidor deve validar) | Sim (navegador bloqueia leituras) |
Como se defender contra CSRF
Existem várias estratégias comprovadas para mitigar CSRF. Você não precisa de todas, mas sobrepor defesas é sábio.
1. Use tokens anti-CSRF
A defesa mais robusta é incluir um token único e imprevisível em cada requisição que altera estado. O servidor valida o token antes de processar. Os tokens devem estar vinculados à sessão do usuário e não expostos em URLs (para evitar vazamento via cabeçalhos de referrer).
// Exemplo: Gerando e validando um token CSRF em Node.js/Express
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/process', csrfProtection, (req, res) => {
// Token é validado automaticamente
res.send('OK');
});
2. Defina cookies SameSite
Navegadores modernos suportam o atributo SameSite para cookies. Defini-lo como Lax ou Strict impede que o navegador envie cookies em requisições cross-site, o que bloqueia muitos ataques CSRF. Lax permite cookies em navegações de nível superior (por exemplo, clicar em um link), enquanto Strict bloqueia todas as requisições cross-site.
Set-Cookie: sessionId=abc123; SameSite=Lax; Secure; HttpOnly
3. Verifique cabeçalhos Origin e Referer
Verifique o cabeçalho Origin ou Referer nas requisições recebidas. Se não corresponderem ao domínio esperado, rejeite a requisição. Esta é uma camada adicional simples, mas eficaz.
4. Use cabeçalhos personalizados para AJAX
Se sua API é consumida via JavaScript, exija um cabeçalho personalizado como X-Requested-With. Os navegadores aplicam o preflight CORS para cabeçalhos personalizados, então um POST de formulário simples de um site malicioso não o incluirá.
Configurando CORS corretamente
Configurações incorretas de CORS também podem levar a problemas de segurança. O erro mais comum é definir Access-Control-Allow-Origin: * enquanto também permite credenciais. Essa combinação é proibida pelos navegadores, mas desenvolvedores às vezes tentam contorná-la de forma insegura.
Melhores práticas para cabeçalhos CORS
- Especifique origens exatas em vez de curingas quando credenciais estiverem envolvidas.
- Limite os métodos permitidos apenas ao que sua API suporta (por exemplo,
GET, POST). - Restrinja os cabeçalhos permitidos àqueles que sua aplicação realmente usa.
- Defina
Access-Control-Max-Agepara armazenar em cache respostas de preflight e reduzir sobrecarga. - Evite refletir o cabeçalho
Origincegamente; valide-o contra uma lista de permissões.
# Exemplo: Configuração do Nginx para CORS
location /api/ {
if ($http_origin ~* (https://(app|admin)\.example\.com)) {
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
}
if ($request_method = 'OPTIONS') {
return 204;
}
}
Lembre-se de que o CORS é aplicado pelo navegador, não pelo servidor. Não é um substituto para autenticação ou autorização; é uma forma de flexibilizar a política de mesma origem com segurança.
Juntando tudo
Proteger requisições do navegador exige uma abordagem em camadas. Aqui está uma lista de verificação rápida:
- Use tokens anti-CSRF para todas as operações que alteram estado.
- Defina cookies SameSite como
LaxouStrict. - Valide cabeçalhos Origin/Referer no servidor.
- Configure CORS com precisão: liste origens permitidas, limite métodos e evite curingas com credenciais.
- Teste regularmente sua aplicação com scanners de segurança e verificações manuais.
Ao entender os papéis distintos de CSRF e CORS, você pode evitar armadilhas comuns e construir uma aplicação web mais segura.
FAQ
O CORS pode prevenir ataques CSRF?
Não, o CORS não previne CSRF. Ataques CSRF não dependem de ler respostas; eles simplesmente disparam requisições. O CORS controla quais origens podem ler respostas, mas não bloqueia o envio da requisição. Para prevenir CSRF, você precisa de tokens, cookies SameSite ou validação de origem.
É seguro definir Access-Control-Allow-Origin como '*'?
Definir como '*' é seguro apenas se sua API não usar credenciais (cookies, autenticação HTTP). Se credenciais estiverem envolvidas, os navegadores rejeitarão a resposta. Para APIs autenticadas, sempre especifique origens exatas.
Preciso de proteção CSRF se eu usar JWT em cabeçalhos Authorization?
Se você armazenar JWTs em cookies, ainda precisa de proteção CSRF porque os cookies são enviados automaticamente. Se você armazenar JWTs em memória e enviá-los via cabeçalho Authorization, CSRF não é uma preocupação porque o atacante não pode definir cabeçalhos personalizados cross-origin. No entanto, você deve se proteger contra XSS para manter o token seguro.
Pronto para testar os cabeçalhos CORS da sua API? Use nosso Analisador de Logs do Nginx para inspecionar padrões de requisição e identificar tentativas cross-origin suspeitas.