Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

─── AVISO ⚠️ ᴄʟɪǫᴜᴇ ᴀǫᴜɪ

Este proxy implementa filtros básicos (whitelist de origem, bloqueio de User-Agent, bloqueio de destinos privados/SSRF, validação de redirecionamentos e rate limit) que impedem uso trivial, acidental ou automatizado de forma descuidada, como scripts genéricos, scanners simples ou chamadas feitas por engano de domínios não autorizados.

Esses filtros não constituem autenticação forte e não impedem um atacante com conhecimento técnico e intenção deliberada de contornar as proteções. Especificamente:

  • ALLOWED_ORIGINS e BLOCKED_AGENTS dependem dos headers Origin e User-Agent, que são definidos pelo próprio cliente. Dentro de um navegador, o JavaScript não consegue forjar o Origin, o que torna essa checagem eficaz nesse contexto. Fora dele, via curl, scripts ou qualquer ferramenta HTTP, esses valores podem ser declarados livremente para imitar uma requisição legítima, tornando essas duas camadas contornáveis com uma única linha de comando.
  • Este script não possui nenhuma camada de autenticação. Sem isso, qualquer pessoa que descubra a URL do Worker e conheça um domínio da whitelist pode reproduzir uma requisição válida manualmente.

As proteções que continuam eficazes independentemente de quem faz a chamada, por não dependerem de dados informados pelo cliente, são:

  • Bloqueio de hosts de destino (_isHostBlocked), que impede acesso a IPs privados, loopback e proxies encadeados (proteção contra SSRF);
  • Validação de redirecionamentos, em que cada Location é verificado antes de ser seguido;
  • Rate limit por IP, baseado em CF-Connecting-IP, header injetado pela própria Cloudflare e não manipulável pelo cliente.

Para cenários que exigem controle de acesso real (restringir quem consome a API por trás do proxy, não apenas reduzir ruído), recomenda-se adicionar:

  • Autenticação de usuário com tokens de sessão de curta duração;
  • Um backend intermediário que retenha qualquer segredo do lado do servidor, nunca exposto ao cliente.

Use este projeto com essa limitação em mente. Ele foi desenhado para reduzir abuso trivial e uso acidental, não para servir como camada de segurança crítica ou controle de acesso definitivo.


🌐 CORS Proxy para Cloudflare Workers

Deploy to Cloudflare Workers

Cloudflare Workers MIT License GitHub Stars

Proxy CORS robusto para Cloudflare Workers com rate limit, whitelist de origens, bloqueio de bots, proteção contra SSRF e cache opcional via KV.

⚠️ Antes de hospedar, leia isto

O proxy vem, por padrão, com domínios de exemplo na whitelist (ALLOWED_ORIGINS), dentro de src/index.js:

ALLOWED_ORIGINS: [
    'https://seudominio.com',
    'https://www.seudominio.com',
    'http://localhost:3000',
    'http://localhost:5500',
    'http://localhost:8080'
]

Se você fizer o deploy sem alterar essa lista, nenhuma aplicação sua vai conseguir usar o proxy — só os domínios de exemplo (que não são seus) estarão liberados. A comparação de origem é feita por protocolo + host exatos, então não adianta usar um domínio parecido — precisa ser idêntico ao configurado. ⚠️ O botão de Deploy Rápido publica o Worker direto na Cloudflare, sem abrir o código para edição antes. Se você for usar esse botão, edite ALLOWED_ORIGINS depois do deploy, direto no editor do dashboard da Cloudflare (veja o passo a passo em Configuração). Para editar antes de publicar, prefira o Deploy Manual pelo Dashboard ou o Deploy via Wrangler CLI.


📋 Índice


🎯 Sobre o Projeto

Este projeto é um proxy CORS desenvolvido para Cloudflare Workers que permite que aplicações frontend acessem APIs externas sem serem bloqueadas por políticas de CORS (Cross-Origin Resource Sharing).

Ele atua como um intermediário: sua aplicação faz requisições para o Worker, que por sua vez consulta a API de destino e retorna os dados com os headers CORS corretos — tudo isso rodando na borda da rede da Cloudflare, próximo do usuário final.

Casos de Uso

Cenário Como o proxy ajuda
🛠️ Desenvolvimento local Testa APIs que bloqueiam CORS durante o desenvolvimento, sem precisar configurar servidor próprio
📊 Dashboards Consome dados de múltiplas APIs externas sem configurações complexas de cada lado
🔌 Integrações Conecta serviços que não suportam CORS nativamente
🧪 Testes Simula chamadas a APIs em ambientes controlados, com rate limit e whitelist previsíveis

💡 Dica: se você só precisa de algo pontual para testes locais, o Deploy Rápido coloca um proxy funcional no ar em menos de um minuto.


✨ Funcionalidades

Funcionalidade Descrição
🔒 Whitelist de origens Apenas domínios autorizados podem usar o proxy, com comparação exata de protocolo + host
⏱️ Rate limit por IP Limite de requisições por IP, configurável em segundos, baseado apenas no IP real informado pela Cloudflare
🛡️ Bloqueio de bots User-Agents conhecidos (curl, Postman, etc.) são bloqueados como camada extra
🚫 Proteção contra SSRF Bloqueia requisições para IPs privados, loopback e hosts internos
🔁 Validação de redirects Cada redirecionamento é validado manualmente antes de ser seguido
🐱 HTTP.cat integrado Respostas de erro acompanhadas de gatos ilustrativos
🔄 Suporte GET/POST Proxy completo para requisições GET e POST
CORS nativo Headers CORS configurados automaticamente em toda resposta
💾 KV opcional Rate limit persistente entre deploys, com fallback automático em memória
🚀 Alta performance Executado na borda (edge) da Cloudflare, próximo do usuário

🔧 Como Funciona

O diagrama abaixo resume o caminho de uma requisição, da aplicação frontend até a API de destino e de volta:

sequenceDiagram
    autonumber
    participant F as 🖥️ Frontend<br/>(React, Vue, etc.)
    participant W as ☁️ Cloudflare Worker<br/>(Proxy CORS)
    participant A as 🌐 API de Destino<br/>(Externa)

    F->>W: Requisição (GET/POST) + Origin
    W->>W: Verifica whitelist de origens (match exato)
    W->>W: Verifica User-Agent (bloqueio de bots)
    W->>W: Valida host de destino (bloqueio de IPs privados/loopback)
    W->>W: Aplica rate limit por IP (KV ou memória)

    alt Requisição permitida
        W->>A: Encaminha requisição
        A-->>W: Resposta da API (ou redirect)
        W->>W: Valida host de cada redirect antes de seguir
        W-->>F: Resposta + headers CORS
    else Bloqueada
        W-->>F: Erro (403 / 429) + imagem HTTP.cat
    end
Loading

Fluxo da Requisição

  1. O frontend faz uma requisição para o Worker, informando a URL de destino via parâmetro url.
  2. O Worker verifica a origem da requisição contra a whitelist configurada, exigindo protocolo e host idênticos.
  3. Em seguida, verifica se o User-Agent não pertence à lista de bots/clientes bloqueados (proteção auxiliar).
  4. O Worker valida o host de destino, recusando IPs privados, loopback e hosts internamente reservados.
  5. Aplica o rate limit por IP, usando o IP real informado pela Cloudflare, com KV (se configurado) ou memória local.
  6. Se tudo estiver certo, o Worker encaminha a requisição para a API de destino, seguindo e validando redirecionamentos manualmente.
  7. Por fim, retorna a resposta ao frontend já com os headers CORS corretos.

📋 Pré-requisitos

  • Conta Cloudflare (gratuita)
  • (Opcional) Node.js e npm, para deploy via Wrangler CLI
  • (Opcional) KV Namespace, para rate limit persistente entre deploys

📦 Deploy

🚀 Deploy Rápido (Recomendado)

Clique no botão abaixo para fazer o deploy automático:

Deploy to Cloudflare Workers

⚠️ Importante: esse botão publica o Worker imediatamente, com a lista ALLOWED_ORIGINS de exemplo. Depois do deploy, acesse o dashboard da Cloudflare, edite src/index.js e substitua os domínios de exemplo pelos seus próprios domínios (veja Variáveis de Configuração). Enquanto isso não for feito, requisições vindas do seu site serão bloqueadas com erro 403.

📝 Deploy Manual pelo Dashboard

  1. Acesse Cloudflare Workers
  2. Clique em Create Worker
  3. Cole o código de src/index.js
  4. Clique em Save and Deploy
  5. Anote a URL do seu Worker (ex: https://seu-worker.workers.dev)

💻 Deploy via Wrangler CLI

# Clone o repositório
git clone https://github.com/ravenastar-js/cors.git
cd cors

# Instale as dependências
npm install

# Teste localmente
npm run dev

# Faça o deploy
npm run deploy

⚠️ Atenção: confirme se você está autenticado no Wrangler (wrangler login) antes de rodar npm run deploy.


🔧 Configuração

Variáveis de Configuração

Edite o objeto CONFIG no src/index.js:

const CONFIG = {
    RATE_WINDOW: 60,        // Janela de tempo em segundos
    RATE_LIMIT: 30,         // Requisições máximas por janela
    ALLOWED_ORIGINS: [      // Domínios autorizados (whitelist, match exato)
        'https://seudominio.com',
        'https://www.seudominio.com',
        'http://localhost:3000',
        'http://localhost:5500'
    ],
    BLOCKED_AGENTS: [       // User-Agents bloqueados (proteção auxiliar)
        'Postman',
        'curl',
        'python-requests',
        'Go-http-client',
        'node-fetch',
        'axios',
        'insomnia',
        'bruno'
    ],
    BLOCKED_HOSTS: [        // Hosts de destino bloqueados (match exato de hostname)
        'proxy.corsfix.com',
        'api.allorigins.win',
        'cors.isomorphic-git.org'
    ],
    MAX_REDIRECTS: 5        // Máximo de redirects seguidos manualmente
};
Campo Tipo Descrição
RATE_WINDOW number Duração da janela de contagem do rate limit, em segundos
RATE_LIMIT number Quantidade máxima de requisições permitidas dentro da janela
ALLOWED_ORIGINS string[] Lista de domínios autorizados a usar o proxy (comparados por protocolo + host exatos)
BLOCKED_AGENTS string[] Trechos de User-Agent que, se detectados, bloqueiam a requisição
BLOCKED_HOSTS string[] Hostnames de destino bloqueados, além de IPs privados/loopback bloqueados automaticamente
MAX_REDIRECTS number Quantidade máxima de redirecionamentos seguidos antes de recusar a requisição

🚨 Obrigatório: ALLOWED_ORIGINS vem preenchido apenas com domínios de exemplo. Substitua todos eles pelos domínios reais da sua aplicação (e remova os localhost de exemplo se não forem usados) antes — ou logo depois — de colocar o Worker no ar. Sem esse ajuste, o proxy bloqueia todas as origens que não sejam as de exemplo, com erro 403 - 🔒 Origem não autorizada.

🔑 Configurar KV (Recomendado)

Para rate limit persistente entre deploys:

  1. No dashboard do Worker, vá em Settings > Variables
  2. Em KV Namespace Bindings, clique em Add binding
  3. Nome da variável: KV
  4. Selecione um namespace existente ou crie um novo
  5. Clique em Save and Deploy

⚠️ Sem KV, o rate limit funciona normalmente, mas os contadores reiniciam a cada novo deploy.


📡 Uso

URL Base

https://seu-worker.workers.dev/?url=https://api-destino.com/endpoint

Parâmetros

Parâmetro Descrição Obrigatório
url URL codificada da API de destino ✅ Sim

Métodos Suportados

Método Uso
GET Consultas simples
POST Envio de dados (JSON)
OPTIONS Preflight CORS (tratado automaticamente pelo Worker)

📝 Exemplos

Requisição GET (curl)

curl "https://seu-worker.workers.dev/?url=https://api.github.com/users/octocat"

Nota: requisições feitas diretamente via curl são bloqueadas pelo filtro de User-Agent por padrão. Use um -A customizado apenas para testes locais controlados.

Requisição POST (curl)

curl -X POST "https://seu-worker.workers.dev/?url=https://api.exemplo.com/dados" \
  -H "Content-Type: application/json" \
  -d '{"nome": "Fulano", "email": "fulano@email.com"}'

Frontend (JavaScript)

fetch('https://seu-worker.workers.dev/?url=https://api.exemplo.com/dados', {
    method: 'GET',
    headers: { 'Accept': 'application/json' }
})
.then(response => response.json())
.then(data => console.log('Dados:', data))
.catch(error => console.error('Erro:', error));

Frontend com React

import React, { useState, useEffect } from 'react';

const App = () => {
    const [dados, setDados] = useState(null);
    const [carregando, setCarregando] = useState(false);
    const [erro, setErro] = useState(null);

    const buscarDados = async () => {
        setCarregando(true);
        setErro(null);
        try {
            const response = await fetch(
                'https://seu-worker.workers.dev/?url=https://api.exemplo.com/dados'
            );
            const data = await response.json();
            setDados(data);
        } catch (err) {
            setErro(err.message);
        } finally {
            setCarregando(false);
        }
    };

    return (
        <div>
            <button onClick={buscarDados}>Buscar Dados</button>
            {carregando && <p>Carregando...</p>}
            {erro && <p style={{ color: 'red' }}>Erro: {erro}</p>}
            {dados && <pre>{JSON.stringify(dados, null, 2)}</pre>}
        </div>
    );
};

export default App;

Frontend com Vue

<template>
  <div>
    <button @click="buscarDados">Buscar Dados</button>
    <p v-if="carregando">Carregando...</p>
    <p v-if="erro" style="color: red;">Erro: {{ erro }}</p>
    <pre v-if="dados">{{ JSON.stringify(dados, null, 2) }}</pre>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dados: null,
      carregando: false,
      erro: null
    };
  },
  methods: {
    async buscarDados() {
      this.carregando = true;
      this.erro = null;
      try {
        const response = await fetch(
          'https://seu-worker.workers.dev/?url=https://api.exemplo.com/dados'
        );
        this.dados = await response.json();
      } catch (err) {
        this.erro = err.message;
      } finally {
        this.carregando = false;
      }
    }
  }
};
</script>

Integração com Bibliotecas HTTP

Axios

import axios from 'axios';

const proxyUrl = 'https://seu-worker.workers.dev';
const targetUrl = 'https://api.exemplo.com/dados';

axios.get(`${proxyUrl}/?url=${encodeURIComponent(targetUrl)}`)
    .then(response => console.log(response.data))
    .catch(error => console.error(error));

Fetch (com opções avançadas)

const proxyUrl = 'https://seu-worker.workers.dev';
const targetUrl = 'https://api.exemplo.com/dados';

const response = await fetch(`${proxyUrl}/?url=${encodeURIComponent(targetUrl)}`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token_aqui'
    },
    body: JSON.stringify({ chave: 'valor' })
});

const data = await response.json();

💡 Dica: sempre use encodeURIComponent() na URL de destino para evitar problemas com caracteres especiais e parâmetros de query.


🛡️ Segurança

Headers de Segurança

O Worker inclui os seguintes headers em todas as respostas:

Header Valor Descrição
Cache-Control no-cache, no-store, must-revalidate Impede cache de dados potencialmente sensíveis
X-RateLimit-Remaining Número Mostra quantas requisições restam na janela atual
X-Proxy CORS-Proxy-Worker Identifica que a resposta passou pelo proxy

Proteções Implementadas

  • Whitelist de origens com match exato — compara protocolo e host completos, evitando bypass por domínios parecidos ou sufixos maliciosos
  • Rate limit por IP real — usa apenas o IP informado pela própria Cloudflare (CF-Connecting-IP), não confiando em headers que o cliente pode forjar
  • Bloqueio de bots — User-Agents conhecidos (curl, Postman, etc.) são recusados como camada auxiliar, não como única defesa
  • Proteção contra SSRF — recusa requisições para IPs privados (10.x, 172.16-31.x, 192.168.x), loopback (127.x, ::1) e hosts internos (localhost, .local)
  • Proteção contra proxy encadeado — bloqueia hosts de destino específicos por comparação exata de hostname
  • Validação de redirecionamentos — cada Location de redirect é verificado antes de ser seguido, com limite máximo de redirects
  • Validação de URL — apenas URLs http:// ou https:// bem formadas são aceitas

⚠️ Importante: o bloqueio de User-Agent é uma camada auxiliar, não uma garantia de segurança. Qualquer cliente HTTP pode definir um User-Agent arbitrário, então não trate essa lista como controle de acesso — a whitelist de origem e a validação de destino são as defesas principais.


❓ FAQ

O que é CORS?

CORS (Cross-Origin Resource Sharing) é uma política de segurança do navegador que impede que um site faça requisições para um domínio diferente do seu, a menos que esse domínio autorize explicitamente. Este proxy contorna esse bloqueio de forma controlada.

Preciso de uma conta paga da Cloudflare?

Não. O plano gratuito do Cloudflare Workers oferece 100.000 requisições por dia, o que é suficiente para a maioria dos projetos.

Como faço para usar com HTTPS?

O Worker já suporta HTTPS nativamente. Basta usar https:// na URL do seu Worker.

Posso usar com APIs que exigem autenticação?

Sim. Você pode enviar headers de autenticação (como Authorization) nas requisições, tanto em GET quanto em POST.

O rate limit é por IP ou por usuário?

O rate limit é aplicado por IP do cliente (obtido via CF-Connecting-IP), garantindo que cada usuário tenha seu próprio limite independente.

Como vejo o status do rate limit?

O header de resposta X-RateLimit-Remaining mostra quantas requisições ainda restam na janela atual.

Posso aumentar o rate limit?

Sim. Basta alterar a variável RATE_LIMIT no arquivo src/index.js e reimplantar o Worker.

O que acontece se eu atingir o rate limit?

O Worker retorna um erro 429 Too Many Requests, junto com o tempo de espera recomendado.

Como faço para limpar o cache do KV?

O cache do KV expira automaticamente conforme a janela configurada, mas também pode ser limpo manualmente pelo dashboard da Cloudflare.

Posso usar o proxy para acessar endereços internos da minha rede?

Não. O Worker bloqueia automaticamente requisições para IPs privados, loopback e hosts internos (localhost, 192.168.x, 10.x, etc.), como proteção contra SSRF.

Posso usar com WebSockets?

Não. Este proxy foi projetado apenas para requisições HTTP/HTTPS convencionais (GET, POST, OPTIONS).


📄 Licença

Este projeto está licenciado sob a Licença MIT — veja o arquivo LICENSE para mais detalhes.


📌 Links Rápidos

Recurso Link
☁️ Cloudflare Workers workers.cloudflare.com
📖 Documentação da API developers.cloudflare.com/workers
🐱 HTTP.cat http.cat
📘 CORS na MDN developer.mozilla.org — CORS

📞 Suporte

Servidor de Suporte


🌟 Star History

Star History Chart

Feito com 💚 por RavenaStar