─── 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_ORIGINSeBLOCKED_AGENTSdependem dos headersOrigineUser-Agent, que são definidos pelo próprio cliente. Dentro de um navegador, o JavaScript não consegue forjar oOrigin, o que torna essa checagem eficaz nesse contexto. Fora dele, viacurl, 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.
Proxy CORS robusto para Cloudflare Workers com rate limit, whitelist de origens, bloqueio de bots, proteção contra SSRF e cache opcional via KV.
O proxy vem, por padrão, com domínios de exemplo na whitelist (
ALLOWED_ORIGINS), dentro desrc/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, editeALLOWED_ORIGINSdepois 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.
- 🌐 CORS Proxy para Cloudflare Workers
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.
| 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.
| 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 |
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
- O frontend faz uma requisição para o Worker, informando a URL de destino via parâmetro
url. - O Worker verifica a origem da requisição contra a whitelist configurada, exigindo protocolo e host idênticos.
- Em seguida, verifica se o User-Agent não pertence à lista de bots/clientes bloqueados (proteção auxiliar).
- O Worker valida o host de destino, recusando IPs privados, loopback e hosts internamente reservados.
- Aplica o rate limit por IP, usando o IP real informado pela Cloudflare, com KV (se configurado) ou memória local.
- Se tudo estiver certo, o Worker encaminha a requisição para a API de destino, seguindo e validando redirecionamentos manualmente.
- Por fim, retorna a resposta ao frontend já com os headers CORS corretos.
- Conta Cloudflare (gratuita)
- (Opcional) Node.js e npm, para deploy via Wrangler CLI
- (Opcional) KV Namespace, para rate limit persistente entre deploys
Clique no botão abaixo para fazer o deploy automático:
⚠️ Importante: esse botão publica o Worker imediatamente, com a listaALLOWED_ORIGINSde exemplo. Depois do deploy, acesse o dashboard da Cloudflare, editesrc/index.jse 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 erro403.
- Acesse Cloudflare Workers
- Clique em Create Worker
- Cole o código de
src/index.js - Clique em Save and Deploy
- Anote a URL do seu Worker (ex:
https://seu-worker.workers.dev)
# 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 rodarnpm run deploy.
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_ORIGINSvem preenchido apenas com domínios de exemplo. Substitua todos eles pelos domínios reais da sua aplicação (e remova oslocalhostde 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 erro403 - 🔒 Origem não autorizada.
Para rate limit persistente entre deploys:
- No dashboard do Worker, vá em Settings > Variables
- Em KV Namespace Bindings, clique em Add binding
- Nome da variável:
KV - Selecione um namespace existente ou crie um novo
- Clique em Save and Deploy
⚠️ Sem KV, o rate limit funciona normalmente, mas os contadores reiniciam a cada novo deploy.
https://seu-worker.workers.dev/?url=https://api-destino.com/endpoint
| Parâmetro | Descrição | Obrigatório |
|---|---|---|
url |
URL codificada da API de destino | ✅ Sim |
| Método | Uso |
|---|---|
GET |
Consultas simples |
POST |
Envio de dados (JSON) |
OPTIONS |
Preflight CORS (tratado automaticamente pelo Worker) |
curl "https://seu-worker.workers.dev/?url=https://api.github.com/users/octocat"Nota: requisições feitas diretamente via
curlsão bloqueadas pelo filtro de User-Agent por padrão. Use um-Acustomizado apenas para testes locais controlados.
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"}'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));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;<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>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));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.
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 |
- ✅ 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
Locationde redirect é verificado antes de ser seguido, com limite máximo de redirects - ✅ Validação de URL — apenas URLs
http://ouhttps://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.
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).
Este projeto está licenciado sob a Licença MIT — veja o arquivo LICENSE para mais detalhes.
| 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 |