Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

CORS no Node.js

Atualizado em: 5 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

CORS, ou Cross-Origin Resource Sharing, é o mecanismo usado pelos navegadores para decidir se um frontend pode acessar uma API hospedada em outra origem. Uma origem é formada por protocolo, domínio e porta. Alterar qualquer um desses elementos cria outra origem.

CORS não é autenticação e não impede chamadas feitas por servidores, aplicativos móveis, curl ou ferramentas automatizadas. Ele controla principalmente o acesso de scripts executados pelo navegador à resposta.

Instalação no Express

npm install cors
import express from 'express';
import cors from 'cors';

const app = express();

app.use(cors({
  origin: 'https://app.example.com',
}));

Evite usar origin: '*' por padrão em APIs privadas. Uma política aberta pode ser adequada para recursos públicos sem credenciais, mas deve ser uma decisão explícita.

Origem dinâmica

const allowedOrigins = new Set([
  'https://app.example.com',
  'https://admin.example.com',
]);

app.use(cors({
  origin(origin, callback) {
    if (!origin) {
      callback(null, true);
      return;
    }

    if (allowedOrigins.has(origin)) {
      callback(null, true);
      return;
    }

    callback(new Error('Origem não permitida'));
  },
}));

Requisições sem cabeçalho Origin podem vir de clientes não navegadores, health checks ou same-origin. Decida se elas devem ser aceitas com base na autenticação da API.

Credentials

Quando cookies ou autenticação do navegador precisam atravessar origens:

app.use(cors({
  origin: 'https://app.example.com',
  credentials: true,
}));

O frontend também precisa usar credenciais:

await fetch('https://api.example.com/profile', {
  credentials: 'include',
});

Não é válido combinar credenciais com origem curinga. Além disso, cookies cross-site exigem atributos apropriados e proteção CSRF.

Preflight

O navegador envia uma requisição OPTIONS antes de certas chamadas, como métodos não simples, headers personalizados ou Content-Type específico.

OPTIONS /orders HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,content-type

A resposta precisa permitir o método e os headers:

app.use(cors({
  origin: allowedOrigin,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization', 'Idempotency-Key'],
  maxAge: 600,
}));

Preflight cache

Access-Control-Max-Age permite que o navegador reutilize a autorização por um período. Valores altos reduzem OPTIONS, mas atrasam mudanças de política. Comece com alguns minutos e valide compatibilidade.

Headers expostos

O navegador não entrega todos os headers da resposta ao JavaScript. Para expor valores úteis:

app.use(cors({
  origin: allowedOrigin,
  exposedHeaders: [
    'ETag',
    'Retry-After',
    'RateLimit-Limit',
    'RateLimit-Remaining',
  ],
}));

Não exponha headers com tokens, cookies internos ou dados desnecessários.

CORS por rota

const publicCors = cors({ origin: '*' });
const privateCors = cors({
  origin: ['https://app.example.com'],
  credentials: true,
});

app.get('/public/catalog', publicCors, listCatalog);
app.get('/account', privateCors, requireAuth, getAccount);

Separar políticas evita abrir a aplicação inteira para atender uma única rota pública.

Regex e subdomínios

Validar origem com endsWith('.example.com') pode aceitar domínios maliciosos como evil-example.com. Parseie a URL:

function isAllowed(origin) {
  try {
    const url = new URL(origin);
    return url.protocol === 'https:' &&
      (url.hostname === 'example.com' || url.hostname.endsWith('.example.com'));
  } catch {
    return false;
  }
}

Se usuários podem criar subdomínios, confiar em todos eles ainda pode ser inseguro.

Origem null

O valor Origin: null pode surgir em arquivos locais, iframes sandboxed e outros contextos. Não o permita automaticamente. Trate como uma origem específica e avalie o risco.

CORS e CSRF

CORS não substitui proteção CSRF. Um site malicioso pode enviar formulários e requisições simples mesmo sem ler a resposta. Se a autenticação usa cookies, implemente SameSite, tokens CSRF e validação de Origin ou Referer.

CORS e JWT

Um token no header Authorization não é enviado automaticamente pelo navegador, o que reduz alguns cenários de CSRF. Entretanto, XSS pode roubar tokens armazenados no frontend. Escolha armazenamento e políticas de segurança considerando o modelo de ameaça.

Proxy reverso

É comum configurar CORS tanto no proxy quanto no Node.js por engano. Isso pode gerar headers duplicados:

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

Mantenha uma única fonte de verdade ou garanta regras consistentes entre camadas.

Cache e Vary

Quando a resposta muda conforme a origem, inclua Vary: Origin. O middleware costuma cuidar disso. Sem Vary, um CDN pode servir a política de uma origem para outra.

WebSockets

WebSocket não usa CORS da mesma forma, mas o handshake inclui Origin nos navegadores. Valide explicitamente a origem no servidor de WebSocket.

Server-Sent Events

SSE segue CORS porque usa HTTP. Se utilizar cookies cross-origin, configure credentials, origem específica e proteção contra CSRF em endpoints que alteram estado.

Erros no navegador

Quando CORS bloqueia, o JavaScript normalmente recebe um erro genérico. Abra a aba Network e verifique:

  • Origin enviado;
  • resposta OPTIONS;
  • Allow-Origin;
  • Allow-Methods;
  • Allow-Headers;
  • credentials;
  • redirects;
  • headers duplicados.

Testando com curl

curl -i \
  -H 'Origin: https://app.example.com' \
  https://api.example.com/profile

Preflight:

curl -i -X OPTIONS \
  -H 'Origin: https://app.example.com' \
  -H 'Access-Control-Request-Method: POST' \
  -H 'Access-Control-Request-Headers: authorization,content-type' \
  https://api.example.com/orders

Testes automatizados

const response = await request(app)
  .get('/account')
  .set('Origin', 'https://app.example.com');

expect(response.headers['access-control-allow-origin'])
  .toBe('https://app.example.com');

Teste também origem não permitida, preflight, credenciais e headers expostos.

Segurança operacional

Mantenha a lista de origens em configuração validada. Não aceite uma variável com curinga em produção sem alerta. Registre mudanças e remova domínios antigos depois de migrações.

Erros comuns

  • usar curinga com cookies;
  • considerar CORS autenticação;
  • permitir qualquer origem refletindo o header recebido;
  • validar subdomínio com string insegura;
  • esquecer OPTIONS no proxy;
  • não configurar Vary;
  • duplicar headers em duas camadas;
  • achar que CORS elimina CSRF;
  • não testar redirects e erros.

Fluxo recomendado

  1. liste frontends autorizados;
  2. separe rotas públicas e privadas;
  3. permita métodos e headers mínimos;
  4. use origem explícita com credentials;
  5. proteja cookies contra CSRF;
  6. teste preflight;
  7. configure Vary e cache;
  8. monitore rejeições.

Combine CORS com Helmet no Node.js, Cache HTTP, Server-Sent Events e TLS e HTTPS.

Consulte a documentação do middleware cors e a referência de CORS da MDN.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita