CORS: o que é, como funciona e como evitar as vulnerabilidades de má configuração

Entenda o que é CORS, como a Same-Origin Policy protege usuários, quais vulnerabilidades surgem de má configuração e como implementar CORS seguro em APIs e servidores.

Sumário

O relatório OWASP Top 10 lista “Security Misconfiguration” como uma das vulnerabilidades mais prevalentes em aplicações web — e misconfigurações de CORS aparecem consistentemente nas auditorias de segurança como um subconjunto dessa categoria. A causa é frequentemente a mesma: um desenvolvedor encontrou o erro “blocked by CORS policy” no console do navegador, buscou uma solução rápida, e configurou Access-Control-Allow-Origin: * para fazer o erro sumir. O problema desaparece. A vulnerabilidade permanece.

O CORS (Cross-Origin Resource Sharing) é um mecanismo que os navegadores implementam para controlar como scripts em uma página web podem fazer requisições para um domínio diferente daquele que serviu a página. Entendê-lo bem significa entender tanto como ele funciona quando configurado corretamente quanto o que acontece quando a configuração está errada.

A confusão em torno do CORS é compreensível: o mecanismo parece um obstáculo ao desenvolvimento (porque frequentemente bloqueia requisições legítimas durante o desenvolvimento), mas existe por razões de segurança sólidas. Desenvolvedores que entendem o raciocínio por trás do CORS configuram-no de forma mais segura do que aqueles que apenas aprendem quais headers precisam ser adicionados para resolver o erro imediato.

Neste artigo, você vai entender o que é a Same-Origin Policy e por que ela existe, como o CORS estende essa política para permitir requisições controladas entre origens, quais são os headers envolvidos e o que cada um faz, como funcionam requisições simples e preflight, quais vulnerabilidades surgem de má configuração e como implementar CORS corretamente em Node.js e Apache. Se você desenvolve ou audita APIs e aplicações web, este guia tem o que você precisa para acertar a configuração.

Same-Origin Policy: a fundação que torna o CORS necessário

O que define uma “Origem”?

Antes de entender o CORS, é preciso entender o conceito de “origem” (origin). Um navegador considera que dois recursos têm a mesma origem quando compartilham exatamente três componentes:

  • Protocolo (esquema): http:// e https:// são protocolos diferentes
  • Host (domínio): api.example.com e example.com são hosts diferentes
  • Porta: example.com:80 e example.com:3000 são origens diferentes

A tabela abaixo ilustra esse critério aplicado a variações de uma URL base https://example.com:

URLMesma origem?Motivo
https://example.com/pagina✅ SimMesmo protocolo, host e porta
https://example.com:443/api✅ SimPorta 443 é implícita para HTTPS
http://example.com❌ NãoProtocolo diferente
https://api.example.com❌ NãoSubdomínio diferente
https://example.com:8080❌ NãoPorta diferente
https://example.org❌ NãoDomínio diferente

Por que a Same-Origin Policy existe?

A Same-Origin Policy (SOP) é a política que os navegadores implementam para restringir como scripts de uma origem podem interagir com recursos de outra origem. Sem ela, qualquer página maliciosa que um usuário abrisse poderia fazer requisições autenticadas em nome desse usuário para qualquer outro site onde ele estivesse logado.

O cenário de ataque que a SOP previne é direto: imagine que você está logado no seu banco e visita uma página maliciosa em outra aba do navegador. Sem a SOP, o JavaScript da página maliciosa poderia fazer uma requisição para https://banco.com/transferir com os cookies de sessão do banco incluídos automaticamente pelo navegador. O banco processaria a transferência normalmente, sem saber que a requisição veio de uma página que o usuário não autorizou.

A SOP torna isso impossível ao proibir que scripts de https://site-malicioso.com leiam as respostas de requisições feitas para https://banco.com — mesmo que a requisição tecnicamente chegue ao servidor.

💡 Dica: A SOP não impede que um navegador envie uma requisição para outra origem — impede que o script leia a resposta. Essa distinção é crítica para entender por que certas classes de ataques (como CSRF) ainda precisam de proteções adicionais além da SOP.

O papel do CORS: a flexibilização controlada

A SOP resolve o problema de segurança mas cria um problema de funcionalidade: aplicações web modernas precisam legitimamente se comunicar com APIs em domínios diferentes. Uma SPA servida em https://app.example.com precisa chamar uma API em https://api.example.com. Um widget de mapa precisa carregar tiles de https://maps.googleapis.com.

O CORS fornece um mecanismo para que servidores declarem explicitamente quais origens têm permissão para acessar seus recursos — estendendo a SOP de forma controlada em vez de contorná-la. O navegador lê os headers CORS na resposta do servidor e decide se permite que o script acesse os dados retornados.

O ponto fundamental: o CORS é um mecanismo de servidor para navegador. O servidor declara suas políticas; o navegador as aplica. Ferramentas como cURL, Postman e código server-side não estão sujeitos ao CORS — apenas navegadores implementam essa restrição.

Como o CORS funciona: requisições simples e preflight

O navegador classifica requisições cross-origin em duas categorias com tratamentos diferentes.

Requisições simples: sem verificação prévia

Uma requisição se qualifica como “simples” quando cumpre todas as seguintes condições:

  • Método: GET, HEAD ou POST
  • Headers: apenas os padrões permitidos (Accept, Accept-Language, Content-Language, Content-Type com valores específicos)
  • Content-Type: apenas application/x-www-form-urlencoded, multipart/form-data ou text/plain

Para requisições simples, o navegador envia a requisição diretamente ao servidor, incluindo automaticamente o header Origin com a origem do script que fez a chamada:

GET /api/produtos HTTP/1.1
Host: api.example.com
Origin: https://app.example.com

O servidor responde com os headers CORS que descrevem sua política:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com
Content-Type: application/json
[{"id": 1, "nome": "Produto A"}]

O navegador verifica se a origem do script (https://app.example.com) bate com o valor declarado em Access-Control-Allow-Origin. Se bater, o script recebe acesso à resposta. Se não bater, o navegador bloqueia o acesso mesmo que a resposta tenha chegado — e lança o erro familiar has been blocked by CORS policy no console.

⚠️ Atenção: O servidor processou a requisição e devolveu a resposta em ambos os casos. A diferença é que no segundo caso o navegador não deixa o script ler o resultado. Para requisições GET simples, isso geralmente é inofensivo. Para requisições POST que modificam estado no servidor, o servidor já executou a ação antes do navegador decidir se o script pode ler a resposta — o que é relevante para entender os limites da proteção que o CORS oferece contra CSRF.

Preflight requests: verificação antes da ação

Requisições que não se qualificam como simples disparam um mecanismo de verificação prévia chamado preflight. Antes de enviar a requisição real, o navegador envia automaticamente uma requisição OPTIONS ao servidor com headers descrevendo o que pretende fazer:

OPTIONS /api/usuarios/123 HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Authorization, Content-Type

O servidor precisa responder com headers que confirmam quais operações aceita:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 3600

Somente após essa confirmação o navegador envia a requisição real. Se o servidor recusar (ou não responder com os headers corretos), o navegador aborta sem enviar a requisição real — o servidor não chega a processar a ação.

Esse mecanismo de preflight existe por uma razão de segurança específica: requisições que usam métodos como DELETE, PUT ou que incluem headers como Authorization podem ter efeitos colaterais significativos no servidor. A verificação prévia garante que o servidor declarou explicitamente aceitar esse tipo de operação dessa origem antes de executá-la.

Requisições com credenciais: um caso especial

Por padrão, o navegador não inclui cookies e headers de autenticação em requisições cross-origin. Para habilitá-los, tanto o código cliente quanto o servidor precisam declarar isso explicitamente:

No cliente (JavaScript):

fetch('https://api.example.com/perfil', {
  method: 'GET',
  credentials: 'include' // Inclui cookies e headers de auth
})

No servidor:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

Quando credenciais estão envolvidas, o servidor não pode usar Access-Control-Allow-Origin: * — precisa especificar uma origem exata. Isso não é uma limitação arbitrária: permitir credenciais para qualquer origem destruiria completamente a proteção que a SOP oferece.

Os headers CORS: o que cada um faz?

Entender cada header individualmente permite configurá-los com precisão em vez de copiar exemplos sem compreensão.

Headers de requisição (enviados pelo navegador)

Origin — O navegador inclui este header automaticamente em todas as requisições cross-origin, indicando a origem do script que fez a chamada. O servidor usa esse valor para decidir se permite o acesso.

Origin: https://app.example.com

Access-Control-Request-Method — Presente apenas em requisições preflight. Informa ao servidor qual método HTTP a requisição real usará.

Access-Control-Request-Method: PUT

Access-Control-Request-Headers — Também exclusivo de preflight. Lista os headers que a requisição real incluirá.

Access-Control-Request-Headers: Authorization, Content-Type

Headers de resposta (enviados pelo servidor)

Access-Control-Allow-Origin — O header mais fundamental. Define qual(is) origem(ns) pode(m) acessar o recurso.

# Permite apenas uma origem específica
Access-Control-Allow-Origin: https://app.example.com

# Permite qualquer origem (evitar em APIs que lidam com dados sensíveis)
Access-Control-Allow-Origin: *

Access-Control-Allow-Methods — Especifica quais métodos HTTP o servidor aceita da origem permitida. Aparece em respostas a preflight.

Access-Control-Allow-Methods: GET, POST, PUT, DELETE

Access-Control-Allow-Headers — Lista os headers que o servidor aceita na requisição real. Necessário quando a requisição inclui headers personalizados.

Access-Control-Allow-Headers: Authorization, Content-Type, X-Request-ID

Access-Control-Allow-Credentials — Indica se o navegador pode expor a resposta ao JavaScript quando a requisição inclui credenciais. Só funciona com origens explícitas (não com *).

Access-Control-Allow-Credentials: true

Access-Control-Expose-Headers — Por padrão, o JavaScript só pode ler um conjunto limitado de headers da resposta. Este header especifica quais headers adicionais ficam acessíveis ao script.

Access-Control-Expose-Headers: X-Request-ID, X-Total-Count

Access-Control-Max-Age — Define por quantos segundos o navegador pode armazenar em cache os resultados de uma preflight request, evitando que o navegador repita a verificação em cada requisição subsequente.

Access-Control-Max-Age: 3600  # 1 hora

Vulnerabilidades de má configuração: o que acontece quando o CORS fica errado?

A maioria das vulnerabilidades de CORS não surge de um bug na tecnologia — surge de configurações inadequadas que invalidam as proteções que o mecanismo deveria fornecer.

O Wildcard Universal: Access-Control-Allow-Origin: *

Configurar * em Access-Control-Allow-Origin instrui o navegador a permitir que qualquer página na internet acesse o recurso. Para APIs públicas que servem dados genuinamente públicos (notícias, cotações de moeda, dados geográficos), isso pode ser aceitável. Para APIs que retornam dados associados a um usuário autenticado, é uma vulnerabilidade grave.

O ataque é simples: um site malicioso faz uma requisição autenticada para a API com * e lê a resposta. Sem credenciais, o * não permite ler respostas com cookies incluídos — mas se a autenticação usa tokens no header Authorization em vez de cookies, o script malicioso pode incluir o token roubado e ler a resposta normalmente.

Reflexão da origem sem validação

Uma configuração perigosa frequente em servidores que precisam suportar múltiplas origens:

// Código vulnerável — não faça isso
app.use((req, res, next) => {
  const origin = req.headers.origin;
  res.setHeader('Access-Control-Allow-Origin', origin); // Reflete qualquer origem
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  next();
});

Esse padrão é funcionalmente equivalente a * para credenciais — qualquer origem recebe permissão. A diferença é que passa despercebido em revisões de código porque não usa o wildcard explícito, criando uma falsa sensação de que a configuração é restritiva.

Validação de origem com substring match incorreto

Outro padrão vulnerável comum tenta validar a origem mas usa comparação de substring em vez de igualdade exata:

// Código vulnerável — não faça isso
app.use((req, res, next) => {
  const origin = req.headers.origin;
  
  if (origin && origin.includes('example.com')) { // Vulnerável!
    res.setHeader('Access-Control-Allow-Origin', origin);
  }
  
  next();
});

Um atacante registra evil-example.com ou example.com.attacker.com e contorna completamente a validação.

Null Origin: uma armadilha pouco conhecida

O header Origin: null aparece em requisições feitas de arquivos locais (file://), sandboxed iframes e redirecionamentos. Algumas configurações permitem explicitamente a origem null para fins de desenvolvimento:

Access-Control-Allow-Origin: null

O problema: um atacante pode criar um sandboxed iframe que envia Origin: null e, se o servidor aceita essa origem, lê a resposta. Nunca configure null como origem permitida em produção.

⚠️ Atenção: Ferramentas de scanner de segurança como Burp Suite Pro incluem verificações específicas para misconfigurações de CORS, testando reflexão de origem, aceitação de null, e validações baseadas em substring. Em um pentest de aplicação web, CORS misconfiguration é um item padrão da checklist — e frequentemente resulta em apontamentos de severidade média a alta dependendo dos dados expostos.

Configuração segura: como implementar corretamente

Node.js com Express: validação de whitelist

A abordagem mais segura para APIs que precisam aceitar múltiplas origens específicas:

const express = require('express');
const app = express();

// Whitelist de origens permitidas
const ALLOWED_ORIGINS = [
  'https://app.example.com',
  'https://admin.example.com',
  'https://parceiro.trusted-domain.com'
];

// Middleware CORS manual com validação rigorosa
app.use((req, res, next) => {
  const origin = req.headers.origin;

  // Valida contra lista de origens permitidas (comparação exata)
  if (origin && ALLOWED_ORIGINS.includes(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Vary', 'Origin'); // Importante para cache correto
    res.setHeader('Access-Control-Allow-Credentials', 'true');
  }

  // Responde preflight requests
  if (req.method === 'OPTIONS') {
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type');
    res.setHeader('Access-Control-Max-Age', '3600');

    return res.status(204).send();
  }

  next();
});

app.get('/api/dados', (req, res) => {
  res.json({ dados: 'sensíveis' });
});

app.listen(3000);

Usando o middleware cors para cenários mais simples:

const cors = require('cors');

const corsOptions = {
  origin: (origin, callback) => {

    // Permite requisições sem origin (ex: curl, Postman, server-to-server)
    if (!origin) return callback(null, true);
    if (ALLOWED_ORIGINS.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error(`Origem não permitida pela política CORS: ${origin}`));
    }
  },

  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Authorization', 'Content-Type'],
  credentials: true,
  maxAge: 3600
};

app.use(cors(corsOptions));

💡 Dica: O header Vary: Origin é frequentemente esquecido mas é importante para cache. Quando o servidor responde com Access-Control-Allow-Origin variável (dependendo da origem da requisição), adicionar Vary: Origin na resposta instrui proxies e CDNs a não servirem a mesma resposta cacheada para origens diferentes — o que poderia fazer um usuário receber uma resposta com headers CORS destinados a outra origem.

Apache: configuração via .htaccess

<IfModule mod_headers.c>
  # Define origens permitidas (Apache não suporta whitelist diretamente
  # nativa — use SetEnvIf para lógica condicional)
  SetEnvIf Origin "^https://(app|admin)\.example\.com$" CORS_ORIGIN=$0

  Header always set Access-Control-Allow-Origin "%{CORS_ORIGIN}e" \
    env=CORS_ORIGIN

  Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE" \
    env=CORS_ORIGIN

  Header always set Access-Control-Allow-Headers "Authorization, Content-Type" \
    env=CORS_ORIGIN
    
  Header always set Access-Control-Allow-Credentials "true" \
    env=CORS_ORIGIN
    
  Header always set Vary "Origin"

  # Responde requisições preflight
  RewriteEngine On
  RewriteCond %{REQUEST_METHOD} OPTIONS
  RewriteRule ^(.*)$ $1 [R=204,L]
</IfModule>

Nginx: bloco de configuração

location /api/ {
  # Mapa para whitelist de origens (define no bloco http{})
  # http { map $http_origin $cors_origin { ... } }
  
  if ($cors_origin) {
    add_header 'Access-Control-Allow-Origin' $cors_origin always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Vary' 'Origin' always;
  }

  # Trata preflight
  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
    add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
    add_header 'Access-Control-Max-Age' 3600;
    return 204;

  }

  proxy_pass http://backend;
}

CORS e outros mecanismos de segurança: como funcionam em conjunto?

CORS não substitui autenticação

Um equívoco comum: tratar a política CORS como mecanismo de autenticação. O CORS controla quais origens o navegador permite fazer requisições — não autentica quem faz a requisição.

Um usuário malicioso com Postman, curl ou qualquer código server-side pode enviar requisições para sua API sem nenhum header Origin, contornando completamente o CORS. A API precisa autenticar e autorizar todas as requisições independentemente de qualquer política CORS configurada.

CORS e autenticação trabalham em camadas diferentes:

  • CORS — controla o que o navegador permite que scripts de outras origens façam
  • Autenticação (tokens JWT, session cookies, API keys) — verifica a identidade do chamador
  • Autorização — verifica se o chamador tem permissão para o recurso solicitado

CORS e CSRF: complementares, não substituíveis

A Same-Origin Policy, que o CORS estende, oferece proteção parcial contra CSRF. Requisições cross-origin que precisam de preflight (DELETE, PUT, requisições com Authorization) não chegam ao servidor sem o servidor ter declarado aceitar aquela origem — o que bloqueia ataques CSRF para essa categoria.

Porém, requisições simples (GET com cookies, POST com Content-Type: application/x-www-form-urlencoded) chegam ao servidor mesmo de origens não autorizadas — o navegador simplesmente bloqueia o script de ler a resposta. Se o servidor executa uma ação baseada nessa requisição sem verificar a origem, o CSRF tem sucesso.

A defesa mais robusta contra CSRF combina:

  • SameSite cookies (SameSite=Strict ou SameSite=Lax) — instrui o navegador a não enviar cookies em requisições cross-site
  • CSRF tokens — tokens únicos por sessão que o servidor verifica em todas as requisições que modificam estado
  • Verificação do header Origin ou Referer no servidor para operações críticas

Content Security Policy: prevenindo o XSS antes do CORS

O CORS não impede XSS — um script malicioso injetado dentro da própria página opera na mesma origem que a página e pode fazer qualquer requisição que o script legítimo faria.

O Content Security Policy (CSP) trabalha como camada complementar: instrui o navegador de quais fontes pode carregar scripts, estilos e outros recursos. Um CSP bem configurado previne que scripts maliciosos injetados via XSS executem, reduzindo o risco de que credenciais ou dados sensíveis sejam exfiltrados mesmo que uma vulnerabilidade de XSS exista.

Diagnóstico de problemas de CORS: abordagem sistemática

Usando DevTools para analisar erros

O erro mais comum — has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present — tem causas distintas que exigem diagnósticos diferentes.

Verificação na aba Network: Selecione a requisição com erro, verifique a aba Headers, e confirme:

  1. O navegador enviou o header Origin na requisição?
  2. A resposta do servidor inclui Access-Control-Allow-Origin?
  3. O valor de Access-Control-Allow-Origin bate com a origem da requisição?

Se a resposta retorna status 5xx ou sem os headers CORS, o problema está no servidor, não na configuração CORS em si — um erro de aplicação antes do middleware CORS executar pode impedir que os headers sejam adicionados.

Para preflight: Filtre requisições OPTIONS na aba Network. Uma preflight com resposta incorreta mostra exatamente quais headers o servidor declarou aceitar versus o que a requisição real precisava.

Erros comuns e suas causas reais

“No ‘Access-Control-Allow-Origin’ header” — O servidor não está retornando o header. Causas possíveis: middleware CORS não configurado, middleware configurado após o roteamento (ordem importa), ou a requisição retornou erro antes do middleware CORS executar.

“The CORS policy does not allow access from this origin” — O servidor retornou Access-Control-Allow-Origin mas com um valor diferente da origem atual. Verifique se a URL exata (incluindo porta) está na whitelist — https://app.example.com e https://app.example.com:3000 são origens diferentes.

“Response to preflight has invalid HTTP status code” — O servidor retornou um status 4xx ou 5xx para a requisição OPTIONS. O servidor precisa responder preflight com 200 ou 204.

“Credential flag is true, but the ‘Access-Control-Allow-Credentials’ header is ”” — O cliente enviou credentials: ‘include’ mas o servidor não retornou Access-Control-Allow-Credentials: true. Além de adicionar esse header, certifique-se de que Access-Control-Allow-Origin especifica uma origem exata (não *).

// Ferramenta útil: teste de configuração CORS via curl
// Simula preflight request para verificar headers do servidor
curl -X OPTIONS https://api.example.com/dados \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: PUT" \
  -H "Access-Control-Request-Headers: Authorization" \
  -v 2>&1 | grep -E "Access-Control|HTTP/"

Checklist de segurança para configuração de CORS

Uma configuração CORS segura em produção deve verificar todos os seguintes pontos:

Controle de origens:

  • Access-Control-Allow-Origin nunca usa * em APIs que retornam dados de usuário
  • A validação de origens usa comparação exata (não substring match ou regex permissivo)
  • A origem null não está na whitelist
  • O header Vary: Origin está presente em respostas com Access-Control-Allow-Origin dinâmico

Controle de métodos e headers:

  • Access-Control-Allow-Methods lista apenas os métodos que a API realmente usa
  • Access-Control-Allow-Headers lista apenas os headers necessários
  • Access-Control-Expose-Headers expõe apenas os headers que o cliente realmente precisa

Credenciais:

  • Access-Control-Allow-Credentials: true aparece apenas quando necessário
  • Quando credenciais estão habilitadas, Access-Control-Allow-Origin nunca usa *
  • Cookies usam SameSite=Strict ou SameSite=Lax como defesa complementar

Performance e cache:

  • Access-Control-Max-Age está configurado com valor adequado para reduzir preflight requests repetidos
  • CDNs e proxies estão configurados para respeitar o header Vary: Origin

Auditoria:

  • A configuração CORS foi testada com ferramentas de scanner (Burp Suite, CORS scanner)
  • Revisão periódica da whitelist para remover origens obsoletas

Perguntas frequentes sobre CORS e segurança

CORS bloqueia requisições de ferramentas como Postman e curl?


Não. O CORS é implementado pelos navegadores e não tem efeito em requisições feitas por código server-side, curl, Postman, ou qualquer cliente que não seja um navegador web. Isso é deliberado: o CORS protege usuários de navegadores contra páginas maliciosas, não protege APIs contra acesso direto. Para proteger APIs contra acesso não autorizado independentemente do cliente, você precisa de autenticação e autorização no servidor.

É seguro usar Access-Control-Allow-Origin: * para APIs públicas?


Depende do que a API retorna. Para recursos genuinamente públicos — dados que qualquer pessoa pode acessar sem autenticação — o wildcard é aceitável. Para APIs que retornam qualquer dado associado a um usuário específico, mesmo que aparentemente público, o wildcard é problemático porque permite que páginas maliciosas leiam esses dados em nome do usuário autenticado. A regra prática: se a resposta da API muda dependendo de quem está autenticado, não use *.

Por que preflight requests existem? Por que não apenas verificar na requisição real?


Requisições que passam por preflight geralmente têm efeitos colaterais no servidor (DELETE, PUT, requisições com Authorization). Se o navegador enviasse a requisição real e só então verificasse a política CORS, o servidor já teria executado a ação antes do navegador descobrir que não deveria ter permitido. O preflight inverte essa ordem: verifica a permissão antes de qualquer ação. Para requisições simples (GET sem headers especiais), o risco de efeito colateral é menor, então o preflight não é necessário.

Como o CORS interage com autenticação via JWT no header Authorization?


Qualquer requisição que inclua o header Authorization automaticamente aciona um preflight, pois esse header não está na lista de headers “simples”. O servidor precisa incluir Authorization no Access-Control-Allow-Headers da resposta preflight para que a requisição real prossiga. Para APIs que usam JWT, a configuração mínima necessária inclui Access-Control-Allow-Headers: Authorization, Content-Type e Access-Control-Allow-Methods com os métodos usados pela API.

Como auditar se uma API tem misconfigurações de CORS?


A abordagem manual mais rápida usa curl para enviar requisições com diferentes valores de Origin e verificar como o servidor responde: curl -H “Origin: https://evil.com” -v https://api.target.com/endpoint 2>&1 | grep “Access-Control”. Se o servidor reflete qualquer origem ou retorna * para endpoints com dados sensíveis, a configuração é problemática. Ferramentas automatizadas como o plugin CORS Scanner do Burp Suite e ferramentas de linha de comando como corsy automatizam testes mais abrangentes, incluindo variações como null origin, subdomain bypass, e protocolo bypass.

CORS seguro é CORS entendido

Ao longo deste artigo, o CORS revelou-se um mecanismo bem desenhado que resolve um problema real — permitir comunicação legítima entre origens diferentes sem comprometer a proteção que a Same-Origin Policy oferece. O problema não está no CORS em si, mas na tendência de configurá-lo para resolver erros em vez de configurá-lo para expressar intenções de segurança.

Toda decisão de configuração de CORS tem uma implicação de segurança: * no Allow-Origin versus uma whitelist explícita, credentials: include com Allow-Credentials: true versus requisições sem credenciais, exposição de headers adicionais versus mínimo necessário. Entender o que cada decisão significa transforma a configuração de CORS de um exercício de “fazer funcionar” para um exercício de “declarar política de segurança”.

Os três princípios que definem uma configuração CORS segura são sempre os mesmos: mínimo privilégio (permita apenas o necessário — origens, métodos e headers específicos), validação rigorosa (comparação exata de origens, nunca substring match), e defesa em profundidade (CORS complementado por autenticação robusta, CSP, tokens CSRF e cookies com atributos SameSite).

Auditar sua configuração CORS periodicamente — especialmente quando novas origens são adicionadas, quando APIs evoluem e quando o time de desenvolvimento muda — é parte da manutenção de segurança que nenhum sistema que aceita requisições cross-origin pode ignorar.

👉 Compartilhe este artigo com desenvolvedores e times de segurança que trabalham com APIs e aplicações web — pode ser a referência que transforma a configuração de CORS de um problema recorrente em uma decisão consciente de política de segurança.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *