Gerenciamento de Requisições Cross-Origin e Implementação CORS

Definição de Origem Cruzada

O conceito de cross-origin surge quando um documento web tenta acessar recursos hospedados em uma origem distinta, seja por diferença no protocolo, domínio ou porta. Por motivos de segurança, os navegadores modernos bloqueiam essas requisições por padrão, fundamentados na Política de Mesma Origem (Same-Origin Policy). Esta机制 visa impedir interações maliciosas entre recursos de fontes não confiáveis.

Regras da Política de Mesma Origem

Para que duas origens sejam consideradas iguais, elas devem compartilhar exatamente os seguintes atributos:

  • Protocolo: Ambos devem utilizar o mesmo esquema (ex: HTTP ou HTTPS).
  • Domínio: O hostname deve ser idêntico (ex: muedominio.com).
  • Porta: O número da porta deve coincidir (ex: 80, 443 ou 3000).

Caso qualquer um desses três elementos difira, o navegador classifica a interação como跨域 (cross-origin) e aplica as restrições de segurança.

Cenários Comuns de Violação

Requisições跨域 são iniciadas pelo cliente (browser) quando há tentativa de comunicação com um endpoint externo. Abaixo estão exemplos práticos de situações que acionam essas restrições:

1. Domínios Distintos

// Página atual: https://loja.virtual.com
fetch('https://servicos.terceiros.net/v1/dados'); // Bloqueado por domínio diferente

2. Subdomínios Diferentes

// Página atual: https://app.loja.virtual.com
fetch('https://api.loja.virtual.com/recursos'); // Bloqueado por subdomínio diferente

3. Protocolos Incompatíveis

// Página atual: https://secure.site.com
fetch('http://insecure.site.com/info'); // Bloqueado por HTTP vs HTTPS

4. Portas Divergentes

// Página atual: http://localhost:3000
fetch('http://localhost:8080/api'); // Bloqueado por porta diferente

Estratégias para Contornar Restrições

Existem diversas abordagens técnicas para permitir comunicação legítima entre origens diferentes, dependendo dos requisitos do projeto.

1. Técnica JSONP (JSON with Padding)

Método legado que explora a permissão de execução de scripts externos. Funciona apenas para requisições GET, inserindo dinamicamente uma tag script no DOM.

<script>
    function callbackDados(payload) {
        console.log('Dados recebidos:', payload);
    }

    const tagScript = document.createElement('script');
    tagScript.src = 'https://api.legada.com/info?fn=callbackDados';
    document.body.appendChild(tagScript);
</script>

2. Padrão CORS (Cross-Origin Resource Sharing)

Solução moderna baseada em cabeçalhos HTTP. O servidor deve explicitamente autorizar origens específicas através de headers de resposta.

Access-Control-Allow-Origin: https://app.cliente.com.br
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type

Em ambientes Node.js com Express, isso pode ser configurado via middleware:

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

const middlewareCors = (req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'https://app.cliente.com.br');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    next();
};

app.use(middlewareCors);

app.get('/recurso', (req, res) => {
    res.json({ status: 'Acesso permitido via CORS' });
});

app.listen(4000, () => {
    console.log('Servidor ativo na porta 4000');
});

3. Proxy Reverso

Configurar um intermediário no mesmo domínio do front-end que repassa as requisições ao back-end real, eliminando a diferença de origem para o navegador.

const { createProxyMiddleware } = require('http-proxy-middleware');

const configProxy = createProxyMiddleware({
    target: 'https://backend.real.com',
    changeOrigin: true,
});

app.use('/gateway', configProxy);

4. Comunicação via Iframe e postMessage

Permite troca de mensagens segura entre janelas de origens diferentes embutidas na página.

<!-- Página Pai -->
<iframe id="frameExterno" src="https://dominio-externo.com"></iframe>
<script>
    const frame = document.getElementById('frameExterno');
    window.addEventListener('message', (evento) => {
        console.log('Mensagem do iframe:', evento.data);
    });
    frame.contentWindow.postMessage('Solicitação segura', 'https://dominio-externo.com');
</script>

Configuração CORS no Spring Framework

Aplicações Java baseadas em Spring seguem a política de mesma origem por padrão. É necessário configurar explicitamente o compartilhamento de recursos.

Configuração Global via WebMvcConfigurer

Implemente a interface de configuração para aplicar regras a toda a aplicação.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ConfiguracaoWeb implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registro) {
        registro.addMapping("/**")
                .allowedOrigins("https://dominio-autorizado.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

Configuração via Anotação @CrossOrigin

Permite definir permissões diretamente no controller ou em métodos específicos.

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin(origins = "https://app.cliente.com.br")
@RestController
public class ControladorDados {

    @GetMapping("/endpoint/seguro")
    public String obterInformacao() {
        return "Dados acessíveis via CORS configurado";
    }
}

Implementação via Filtro Servlet

Para controle granular, um filtro personalizado pode manipular diretamente a resposta HTTP.

import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class FiltroAcessoCors implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
            throws IOException, ServletException {
        
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        
        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}
}

Tags: CORS spring-boot javascript Web-Security backend

Publicado em 8-25 13:32