Uma API que funciona depois que você adiciona Access-Control-Allow-Origin não é necessariamente segura. O CORS não é algo que você adiciona uma vez e esquece; o que importa é estreitar quem você permite. Veja como ele funciona e como configurá-lo com segurança (sem passos de ataque).
Primeiro, como funciona
Os navegadores aplicam uma política de mesma origem: o JS de outra origem não pode ler livremente as respostas de outro site. O CORS existe para abrir essa exceção apenas às partes que o servidor permite explicitamente.
Uma origem é a combinação de esquema (https), nome de host e porta. https://example.com e https://api.example.com têm hosts diferentes, então são origens diferentes; http://example.com e https://example.com diferem no esquema, então também são diferentes.
| Cabeçalho de resposta | Significado |
|---|---|
Access-Control-Allow-Origin | Quais origens podem ler a resposta |
Access-Control-Allow-Credentials | Se requisições com credenciais (cookies) são permitidas |
Access-Control-Allow-Methods / -Headers | Quais métodos/cabeçalhos HTTP são permitidos |
O ponto: o CORS está do lado do "afrouxar a restrição". Afrouxe-o errado e dados que não deveriam ser legíveis se tornam legíveis por terceiros.
Mais um detalhe importante: o que o CORS impede é que o JavaScript leia a resposta. Uma requisição simples chega ao servidor e é processada mesmo sem permissão de CORS. Em casos como cabeçalhos personalizados, o navegador primeiro consulta o servidor com uma requisição OPTIONS (preflight) e não envia a requisição real se ela não for permitida.
Como ele se diferencia de mecanismos parecidos
O CORS é frequentemente confundido com mecanismos de nome parecido e com uma vulnerabilidade muito próxima.
| Termo | O que decide | Quem aplica |
|---|---|---|
| Política de mesma origem | Outras origens não podem ler respostas (padrão do navegador) | O navegador |
| CORS | Como exceção a isso, quais origens podem ler | O servidor declara, o navegador aplica |
| CSRF | Um ataque que faz o navegador logado do usuário enviar requisições não desejadas | Evitado com tokens CSRF e SameSite |
| CSP | Quais scripts e conexões a sua própria página pode carregar | O servidor declara, o navegador aplica |
O CORS trata de "a resposta pode ser lida?"; o CSRF trata de "uma requisição pode ser enviada em nome do usuário?". Endurecer o CORS não evita CSRF.
O que torna uma configuração perigosa
Configurações perigosas (comuns)
- Refletir a Origin da requisição de volta como permitida
Access-Control-Allow-Origin: *mais permitir credenciais- Abrir APIs amplamente para origem cruzada que não precisam disso
Configurações seguras
- Uma lista de permissões (apenas origens fixas e confiáveis)
- Negar por padrão para todo o resto
- Para requisições com credenciais, uma origem específica, não
*
Como as configurações incorretas costumam surgir
A maioria das configurações incorretas nasce da tentativa de fazer um erro de CORS sumir. A sequência típica:
- Chamar a API a partir do front-end com cookies gera um erro de CORS
- Você adiciona
Access-Control-Allow-Origin: *. Mas, em requisições com credenciais, o navegador não deixa a página ler uma resposta com*, então o erro continua - Você passa a devolver a
Originque chegou, e o erro desaparece. Ao mesmo tempo, qualquer site agora pode ler respostas de usuários logados
Mesmo com uma lista de permissões, uma comparação descuidada leva ao mesmo lugar.
- Comparar "termina com
example.com" também deixa passar outro domínio, comoevil-example.com - Comparar "começa com
https://example.com" também deixa passarhttps://example.com.evil.net - Permitir a origem
nullpor conveniência no desenvolvimento também permite leituras a partir de origensnullque outros sites conseguem produzir
Compare a origem inteira (esquema, host e porta) buscando correspondência exata.
Os fundamentos de uma configuração segura
Use uma lista de permissões (o mais importante)
Não reflita a Origin cegamente
Origin da requisição diretamente em Access-Control-Allow-Origin. Retorne-a apenas quando ela corresponder à lista de permissões. Como o valor passa a variar por requisição, envie também Vary: Origin para que os caches não misturem respostas.Nunca use * com credenciais
Access-Control-Allow-Origin: * com Allow-Credentials: true. Nomeie uma origem específica em vez disso.Minimize o que você abre
* apenas para dados públicos que não exigem login.Como verificar o seu próprio site
Envie à sua API uma requisição que declare outra origem e observe os cabeçalhos de resposta. Faça isso apenas contra APIs que você administra.
# Declare uma origem que você não permitiu e veja apenas os cabeçalhos de resposta
curl -s -o /dev/null -D - -H "Origin: https://example.com" https://your-api.example/ | grep -i "^access-control"- Se voltar
Access-Control-Allow-Origin: https://example.com, a API está refletindo a Origin. Adicione a comparação com a lista de permissões - Se aparecerem juntos
Access-Control-Allow-Origin: *eAccess-Control-Allow-Credentials: true, revise a configuração - Se nada voltar, ou voltar apenas a origem do seu próprio front-end, está tudo certo
Repita a mesma verificação com Origin: null. Para um site cuja propriedade você verificou, a auditoria de segurança do site checa a reflexão da origem e as configurações de credenciais em conjunto. Os demais cabeçalhos de segurança podem ser verificados com o verificador de cabeçalhos de segurança.
A visão deste site: o CORS é 'como você afrouxa', não 'defesa' — estreite a quem você abre
Uma crença equivocada comum é "adicionar cabeçalhos CORS torna seguro". É o contrário: o CORS afrouxa a restrição do navegador. Então o que importa não é "como você adiciona", mas "minimizar a quem, e até onde, você abre."
Neste site separamos dados que podem ser lidos externamente dos que não podem, e recomendamos negar por padrão, com uma lista de permissões abrindo apenas as exceções. Note que XSS (que quebra a premissa de leitura) e CSRF (que tem como alvo mudanças de estado) são bugs separados — o CORS sozinho não cobre tudo.
Fontes (primárias)
- MDN Web Docs, "Cross-Origin Resource Sharing (CORS)" (em inglês) — developer.mozilla.org (sem * em requisições com credenciais, condições do preflight, Vary: Origin)
- WHATWG Fetch Standard, "CORS protocol" (em inglês) — fetch.spec.whatwg.org
- OWASP HTML5 Security Cheat Sheet (em inglês) — cheatsheetseries.owasp.org (permitir apenas domínios confiáveis; não devolver o cabeçalho Origin sem checagem)
- PortSwigger Web Security Academy, "Cross-origin resource sharing (CORS)" (em inglês) — portswigger.net (erros na comparação com a lista de permissões, a origem null, CORS não é proteção contra CSRF)
- MITRE CWE-942: Permissive Cross-domain Policy with Untrusted Domains (em inglês) — cwe.mitre.org
Leia a seguir
- Glossário: O que é XSS · O que é CSRF · O que é um JWT
- Aprenda: Escolhendo cabeçalhos de segurança (em inglês)
- Verifique: Verificador de cabeçalhos de segurança · Auditoria de segurança do site