Análise de CORS e Soluções Comuns para Comunicação Entre Domínios

Compreendendo o Problema de CORS

Em uma aplicação web moderna, é comum que o front-end (rodando em um domínio, como http://app.exemplo.com) precise solicitar recursos de uma API hospedada em outro domínio (como http://api.exemplo.com). Essa é uma situação de CORS (Cross-Origin Resource Sharing), que viola a Política de Mesma Origem (Same-Origin Policy) dos navegadores. Por padrão, o navegador bloqueia tais requisições por razões de segurança.

O Mecanismo do CORS

O CORS é um mecanismo padrão da W3C que permite que um servidor especifique explicitamente quais origens externas têm permissão para acessar seus recursos. O processo varia dependendo se a requisição é considerada "simples" ou não.

Requisições Simples: Atendem a condições específicas, como usar apenas os métodos GET, POST ou HEAD, e possuir um Content-Type limitado (por exemplo, text/plain). Para essas, o navegador inclui automaticamente o cabeçalho Origin na requisição. O servidor responde com Access-Control-Allow-Origin indicando as origens permitidas.

Requisições Não-Simples (Pré-flight): Para requisições mais complexas (ex.: com cabeçalhos personalizados ou métodos como PUT/DELETE), o navegador envia automaticamente uma requisição OPTIONS (conhecida como "pré-flight") para o servidor. Essa requisição verifica se a requisição principal é permitida. A resposta do servidor inclui cabeçalhos como Access-Control-Allow-Methods e Access-Control-Allow-Headers.

Configuração no Servidor com Nginx

Uma abordagem comum é configurar o Nginx atuando como proxy reverso para adicionar os cabeçalhos CORS necessários. Abaixo um exemplo de configuração:

location /api/ {
    # Lida com a requisição de pré-flight OPTIONS
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' 'http://app.exemplo.com';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
    }

    # Adiciona os cabeçalhos CORS para requisições reais
    add_header 'Access-Control-Allow-Origin' 'http://app.exemplo.com' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization' always;

    proxy_pass http://backend_server;
}

Um ponto de atenção: configurar Access-Control-Allow-Headers com o curinga * pode causar problemas em navegadores mais antigos como o IE11. É uma prática mais segura listar os cabeçalhos necessários explicitamente.

Configuração no Backend com Spring Boot (Java)

No ecossistema Spring, é possível configurar o CORS globalmente usando um filtro. Isso garante que a configuração seja aplicada antes de qualquer interceptor da aplicação, evitando conflitos de ordem de execução.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("http://app.exemplo.com"); // Use allowedOriginPattern para flexibilidade
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return new CorsFilter(source);
    }
}

Nota importante: O método addAllowedOrigin("*") geralmente não é recomendado quando allowCredentials é true. Em vez disso, use addAllowedOriginPattern para listar origens específicas de forma segura.

Código de Resposta da Pré-flight: 200 vs 204

Existe uma variação na prática entre diferentes ferramentas. O código de status 200 é amplamente utilizado e funciona sem problemas. O código 204 (No Content) é semanticamente mais preciso para uma resposta OPTIONS que apenas confirma permissões sem corpo de mensagem. Ambos os códigos são suportados pelos navegadores modernos. A escolha depende muitas vezes da convenção adotada pelo framework ou servidor proxy utilizado.

O Novo Desafio: Redes Privadas Não-Seguras (CORS-RFC1918)

A partir do Chrome 94, uma nova política restringe requisições de páginas na internet pública para servidores em redes privadas (endereços IP como 192.168.x.x ou 10.x.x.x), a menos que a comunicação seja via HTTPS. Isso pode gerar erros como InsecurePrivateNetwork.

Soluções recomendadas:

  1. Migre para HTTPS: A solução definitiva. Implemente certificados TLS (podem ser gerados intrenamente) para todos os endpoints da sua rede interna.
  2. Ajustes temporários no navegador: Desative a flag #block-insecure-private-network-requests no chrome://flags para testes.
  3. Ajustes de rede: Acesse o serviço privado usando um hostname que resolva para um IP público ou utilize um túnel (como ngrok) para desenvolvimento.

Considerações de Arquitetura

Para sistemas complexos com múltiplas aplicações front-end, adotar um API Gateway centarlizado pode simplificar significativamente o gerenciamento de CORS. O gateway concentra a configuração de cabeçalhos CORS, autenticação, rate-limiting e roteamento, liberando os microsserviços backend dessa responsabilidade. Ferramentas como Kong, Spring Cloud Gateway ou soluções em nuvem (AWS API Gateway) oferecem essa capacidade.

A compreensão profunda dos mecanismos do CORS, combinada com uma configuração cuidadosa do servidor e atenção a atualizações dos navegadores, é essencial para garantir uma comunicação robusta e segura entre as partes distribuídas de uma aplicação web.

Tags: CORS HTTP Headers web security nginx Spring Boot

Publicado em 7-1 06:30