Introdução: por que "apenas REMOTE_ADDR" já não funciona
Todo desenvolvedor PHP já se perguntou pelo menos uma vez: "Como obter o endereço IP do cliente?". No Stack Overflow, este tópico acumula centenas de milhares de visualizações, e sob a resposta canônica — dezenas de comentários esclarecedores. O problema é que em 2025, o simples $_SERVER['REMOTE_ADDR'] já não é suficiente.
Sites modernos funcionam atrás de CDNs (Cloudflare, Akamai), balanceadores de carga e servidores proxy. Os usuários acessam via VPN ou Tor. E os invasores aprenderam a falsificar cabeçalhos. Se você quer descobrir o verdadeiro endereço IP do visitante — e ao mesmo tempo não abrir a porta para ataques — precisa aplicar práticas comprovadas.
Neste artigo, mostrarei como funciona a determinação de IP em PHP, analisarei as armadilhas e fornecerei um código pronto que pode ser usado com segurança em 2025.
Como o PHP "vê" o endereço IP?
Quando o navegador envia uma requisição ao servidor, o PHP preenche automaticamente o array superglobal $_SERVER. Pelo endereço IP do "interlocutor" responde a chave REMOTE_ADDR. No mundo ideal (sem proxy), este é o IP do cliente:
<?php$ip = $_SERVER['REMOTE_ADDR']; // 192.168.1.5?>Mas na realidade, atrás do servidor frequentemente estão nginx, HAProxy ou Cloudflare. Então REMOTE_ADDR mostra o IP do proxy, não do usuário. O endereço real é transmitido nos cabeçalhos HTTP:
HTTP_X_FORWARDED_FOR— cabeçalho padrão para proxies;HTTP_X_REAL_IP— usado pelo nginx;HTTP_CF_CONNECTING_IP— específico do Cloudflare;HTTP_CLIENT_IP— raro, mas ocorre.
Problema: qualquer um desses cabeçalhos pode ser falsificado. Se você confiar em $_SERVER['HTTP_X_FORWARDED_FOR'] sem verificação, um invasor pode facilmente inserir um IP falso.
REMOTE_ADDR vs X-Forwarded-For: quando usar qual?
Aqui está a regra chave que vai te salvar de dores de cabeça:
- Se o site está diretamente no servidor sem proxy — use apenas
REMOTE_ADDR. - Se o site está atrás de um proxy confiável (CDN, balanceador) — pegue o IP do cabeçalho, mas somente após verificar que a requisição veio exatamente do seu proxy.
Em 2025, o padrão de facto é X-Forwarded-For. Dentro dele pode haver uma cadeia de IPs: cliente, proxy1, proxy2. O primeiro endereço é do cliente, o último é o endereço do último proxy.
Por que não se pode confiar cegamente no X-Forwarded-For?
Imagine: um invasor envia uma requisição com o cabeçalho X-Forwarded-For: 127.0.0.1. Se seu código simplesmente lê $_SERVER['HTTP_X_FORWARDED_FOR'], você obterá 127.0.0.1 (localhost). Logs, análises, geolocalização — tudo quebrará. Pior ainda, o atacante pode inserir o IP de outro usuário para se passar por ele.
Solução: confiar no cabeçalho X-Forwarded-For apenas se REMOTE_ADDR for igual ao IP do seu proxy confiável. De nenhuma outra forma.
Melhor prática de 2025: função universal para obter IP
Reuni uma lógica comprovada que leva em conta todas as realidades modernas. A função:
- Verifica se a requisição passa por proxies confiáveis (você define a lista deles).
- Se sim — extrai o primeiro IP do
X-Forwarded-For. - Se não — retorna
REMOTE_ADDR. - Filtra endereços privados e reservados (opcional).
<?php/** * Obtém o endereço IP real do cliente. * * @param array $trustedProxies Lista de IPs de proxy confiáveis * @return string Endereço IP ou '0.0.0.0' se não foi possível determinar */function getClientIP(array $trustedProxies = []): string { $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';