Procurando o IP do Servidor? Entregue o 'Pastel' via Worker
Este artigo discute como proteger o IP de um servidor de aplicações, especialmente em ambientes móveis, utilizando Cloudflare Workers e WebSockets para criar um túnel reverso. O autor apresenta um exemplo de código e configuração para ocultar o IP do servidor e dificultar ataques.
MundiX News·13 de maio de 2026·5 min de leitura·👁 7 views
A segurança de dispositivos móveis é um desafio constante, pois eles operam em ambientes inerentemente hostis, onde suas conexões podem ser expostas a terceiros. Provedores de Wi-Fi ou LTE, por exemplo, têm acesso a essas informações, o que pode comprometer a segurança do servidor de aplicações ou do proxy de entrada.
Uma solução é esconder o servidor atrás do Cloudflare e configurar o acesso através de um IP 'limpo' do Cloudflare, sem usar consultas DNS. O roteamento é feito pelo próprio Cloudflare usando SNI (Server Name Indication) dedicado, mantendo o handshake aberto para evitar suspeitas. No entanto, quando essa abordagem não é viável, é possível criar um mecanismo semelhante utilizando WebSockets e Cloudflare Workers. A ideia é usar um domínio com DNS do Cloudflare para o SNI, como subdomínios gratuitos do DigitalPlat. O worker encaminha o fluxo WebSocket para o servidor de aplicações com um IP fixo, e o uso de certificados Let's Encrypt para IPs garante a criptografia. Para evitar que o endereço IP do servidor de aplicações seja descoberto a partir de solicitações de saída, um servidor separado com um IP diferente pode ser usado para essas solicitações. Desta forma, a conexão entre as conexões de saída do dispositivo móvel e as solicitações do servidor de aplicações, bem como o IP do servidor de aplicações, torna-se praticamente impossível de rastrear.
O artigo fornece um exemplo de código de um worker com filtragem de endereços permitidos e um endereço dummy do servidor de aplicações. O código inclui a extração do IP do cliente, a verificação do IP (permitindo apenas endereços específicos) e a configuração de um WebSocket para estabelecer uma conexão com o servidor de aplicações. O código também inclui funções para lidar com a comunicação WebSocket, proxy de dados e otimização da transferência de dados do TCP para o WebSocket. Para conectar-se ao worker a partir de um dispositivo móvel, o autor sugere o uso do hiddify com uma configuração específica que inclui a configuração de um túnel VLESS via WebSocket. O tráfego entre o worker e o próximo servidor na cadeia não é criptografado para reduzir a sobrecarga, mas a criptografia pode ser implementada no servidor final. A exclusividade da conexão é garantida pelo UUID.
javascript
import{ connect }from'cloudflare:sockets';exportdefault{asyncfetch(request, env, ctx){// 1. Extrai o IPconst clientIP = request.headers.get("CF-Connecting-IP");// 2. Verificaconst allowedIPv4 ="127.0.0.1";// Não se esqueça de mudarconst allowedIPv6Prefix ="fe80:";// Observe os dois pontos no final e não se esqueça de mudarif(clientIP !== allowedIPv4 &&!clientIP.startsWith(allowedIPv6Prefix)){returnnewResponse(clientIP +" -> Quem são vocês?",{status:403});}const upgradeHeader = request.headers.get('Upgrade');if(!upgradeHeader || upgradeHeader !=='websocket'){returnnewResponse('Bridge Ativo.',{status:200});}const vlConfig ={address:'10.0.0.1',port:8080,};// não se esqueça de mudar o endereço e a porta para o seuconst webSocketPair =newWebSocketPair();const[client, server]=Object.values(webSocketPair); server.accept();handleProxy(server, vlConfig);returnnewResponse(null,{status:101,webSocket: client,});}};asyncfunctionhandleProxy(ws, config){let tcpSocket =null;let writer =null; ws.addEventListener('message',async(event)=>{try{const data = event.datainstanceofArrayBuffer? event.data:awaitnewResponse(event.data).arrayBuffer();if(!tcpSocket){// Inicializa a conexão tcpSocket =connect({hostname: config.address,port: config.port}); writer = tcpSocket.writable.getWriter();// Inicia a leitura de alto desempenhocopyTcpToWs(tcpSocket.readable, ws);}await writer.write(newUint8Array(data));}catch(err){ ws.close(1011);}}); ws.addEventListener('close',()=>{if(tcpSocket) tcpSocket.close();}); ws.addEventListener('error',()=>{if(tcpSocket) tcpSocket.close();});}/**
* Transferência otimizada de dados do TCP para o WebSocket
*/asyncfunctioncopyTcpToWs(tcpReadable, ws){try{// Usa o mecanismo de streams integrado para minimizar a carga na CPUawait tcpReadable.pipeTo(newWritableStream({write(chunk){ ws.send(chunk);},close(){ ws.close();},abort(reason){ ws.close(1011);}}));}catch(err){try{ ws.close();}catch(e){}}}
Sem cartão para começar · Planos a partir de R$49/mês
A segurança de dispositivos móveis é um desafio constante, pois eles operam em ambientes inerentemente hostis, onde suas conexões podem ser expostas a terceiros. Provedores de Wi-Fi ou LTE, por exemplo, têm acesso a essas informações, o que pode comprometer a segurança do servidor de aplicações ou do proxy de entrada.
Uma solução é esconder o servidor atrás do Cloudflare e configurar o acesso através de um IP 'limpo' do Cloudflare, sem usar consultas DNS. O roteamento é feito pelo próprio Cloudflare usando SNI (Server Name Indication) dedicado, mantendo o handshake aberto para evitar suspeitas. No entanto, quando essa abordagem não é viável, é possível criar um mecanismo semelhante utilizando WebSockets e Cloudflare Workers. A ideia é usar um domínio com DNS do Cloudflare para o SNI, como subdomínios gratuitos do DigitalPlat. O worker encaminha o fluxo WebSocket para o servidor de aplicações com um IP fixo, e o uso de certificados Let's Encrypt para IPs garante a criptografia. Para evitar que o endereço IP do servidor de aplicações seja descoberto a partir de solicitações de saída, um servidor separado com um IP diferente pode ser usado para essas solicitações. Desta forma, a conexão entre as conexões de saída do dispositivo móvel e as solicitações do servidor de aplicações, bem como o IP do servidor de aplicações, torna-se praticamente impossível de rastrear.
O artigo fornece um exemplo de código de um worker com filtragem de endereços permitidos e um endereço dummy do servidor de aplicações. O código inclui a extração do IP do cliente, a verificação do IP (permitindo apenas endereços específicos) e a configuração de um WebSocket para estabelecer uma conexão com o servidor de aplicações. O código também inclui funções para lidar com a comunicação WebSocket, proxy de dados e otimização da transferência de dados do TCP para o WebSocket. Para conectar-se ao worker a partir de um dispositivo móvel, o autor sugere o uso do hiddify com uma configuração específica que inclui a configuração de um túnel VLESS via WebSocket. O tráfego entre o worker e o próximo servidor na cadeia não é criptografado para reduzir a sobrecarga, mas a criptografia pode ser implementada no servidor final. A exclusividade da conexão é garantida pelo UUID.
import { connect } from 'cloudflare:sockets';
export default {
async fetch(request, env, ctx) {
// 1. Extrai o IP
const clientIP = request.headers.get("CF-Connecting-IP");
// 2. Verifica
const allowedIPv4 = "127.0.0.1"; // Não se esqueça de mudar
const allowedIPv6Prefix = "fe80:"; // Observe os dois pontos no final e não se esqueça de mudar
if (clientIP !== allowedIPv4 && !clientIP.startsWith(allowedIPv6Prefix)) {
return new Response(clientIP + " -> Quem são vocês?", { status: 403 });
}
const upgradeHeader = request.headers.get('Upgrade');
if (!upgradeHeader || upgradeHeader !== 'websocket') {
return new Response('Bridge Ativo.', { status: 200 });
}
const vlConfig = {
address: '10.0.0.1',
port: 8080,
}; // não se esqueça de mudar o endereço e a porta para o seu
const webSocketPair = new WebSocketPair();
const [client, server] = Object.values(webSocketPair);
server.accept();
handleProxy(server, vlConfig);
return new Response(null, {
status: 101,
webSocket: client,
});
}
};
async function handleProxy(ws, config) {
let tcpSocket = null;
let writer = null;
ws.addEventListener('message', async (event) => {
try {
const data = event.data instanceof ArrayBuffer ? event.data : await new Response(event.data).arrayBuffer();
if (!tcpSocket) {
// Inicializa a conexão
tcpSocket = connect({ hostname: config.address, port: config.port });
writer = tcpSocket.writable.getWriter();
// Inicia a leitura de alto desempenho
copyTcpToWs(tcpSocket.readable, ws);
}
await writer.write(new Uint8Array(data));
} catch (err) {
ws.close(1011);
}
});
ws.addEventListener('close', () => {
if (tcpSocket) tcpSocket.close();
});
ws.addEventListener('error', () => {
if (tcpSocket) tcpSocket.close();
});
}
/**
* Transferência otimizada de dados do TCP para o WebSocket
*/
async function copyTcpToWs(tcpReadable, ws) {
try {
// Usa o mecanismo de streams integrado para minimizar a carga na CPU
await tcpReadable.pipeTo(new WritableStream({
write(chunk) {
ws.send(chunk);
},
close() {
ws.close();
},
abort(reason) {
ws.close(1011);
}
}));
} catch (err) {
try { ws.close(); } catch (e) { }
}
}
Divulgação: alguns links são patrocinados. Podemos receber comissão se você comprar — sem custo extra para você. Só indicamos o que faz sentido para a comunidade.