Uma requisição que chega à sua aplicação carrega dois tipos de prova do endereço: o par que abriu a conexão de rede e um campo HTTP que afirma o endereço de um cliente anterior. Eles respondem a perguntas diferentes. O par de socket é observado, enquanto o cabeçalho é afirmado por quem o escreveu, e nenhum dos dois deveria substituir o outro silenciosamente em um log ou em uma regra de acesso. A comparação abaixo os mantém separados e depois mostra o único arranjo em que o cabeçalho se torna utilizável.

Descreva o caminho antes de comparar qualquer coisa:

Client -> approved reverse proxy -> application origin

Nesse arranjo, o par de socket da origem normalmente é o proxy, e um cabeçalho de encaminhamento pode carregar a afirmação do proxy sobre o cliente. Seu valor vem da relação controlada com esse proxy, não do nome do cabeçalho.

Dois tipos de prova do endereço

O par de socket é um fato sobre uma conexão TCP: algo completou um aperto de mão a partir daquele endereço. Não é necessariamente a pessoa, o dispositivo ou a conta com que você se importa, porque uma VPN ou uma saída Tor podem ser legitimamente a fonte que um serviço observa. Ainda assim, é o único endereço que o próprio host verificou, e nisso está todo o seu valor.

Um campo de encaminhamento é metadado sobre uma cadeia. X-Forwarded-For, X-Real-IP e o campo padronizado Forwarded podem ser escritos por qualquer cliente que alcance um ponto final que os reflita, então sua confiabilidade depende inteiramente de quem teve permissão para defini-los.

Mantenha os dois no contexto da requisição sob nomes distintos. Uma aplicação que sobrescreve o par com o cabeçalho perde a capacidade de reconstruir mais tarde um erro de confiança, e é exatamente quando você precisa disso.

Um cabeçalho nunca redireciona a conexão

Escrever um endereço em um campo de encaminhamento não muda a origem da conexão TCP que chega ao servidor, nem altera o roteamento em nenhum ponto do caminho. O roteamento VPN comum ou NAT de origem entrega o tráfego sem nenhum cabeçalho HTTP. Da mesma forma, um gateway de trânsito não reescreve uma troca HTTPS bem protegida sem mudar o arranjo do ponto final TLS.

O erro inverso é igualmente comum: HTTPS não torna verdadeiro um cabeçalho de encaminhamento fornecido pelo cliente. Ele protege o transporte de uma afirmação falsa exatamente como o de uma verdadeira.

Se um colega propõe uma mudança de cabeçalho para corrigir um problema de roteamento, o diagnóstico já deu errado. Corrija o caminho ou corrija a configuração do proxy que escreve o cabeçalho.

Nomeie o proxy autorizado a afirmar

Duas regras tornam um campo de encaminhamento utilizável, e ambas são configuração e não código. A borda normaliza ou descarta tudo o que vem de fora, seguindo seu próprio comportamento documentado para esses campos. Depois a origem toma um endereço substituto do caminho de proxy que você nomeou e de nenhum outro lugar. Essa segunda regra só vale enquanto os clientes não conseguem alcançar a origem de outra forma, porque uma origem que responde tanto a requisições diretas quanto a requisições via proxy não sabe qual das duas está servindo.

O módulo de IP real do NGINX mostra a separação com clareza. set_real_ip_from nomeia os remetentes cuja afirmação conta, e real_ip_header diz qual campo a carrega; o primeiro exerce a confiança, o segundo apenas diz onde olhar.

set_real_ip_from 10.20.0.0/24;
real_ip_header X-Forwarded-For;
# real_ip_recursive off - take the rightmost value in the field
# real_ip_recursive on  - walk the list back past every trusted address

Uma diretiva de seleção de cabeçalho por si só ainda não estabelece nada sobre quem enviou o valor.

A segurança do transporte deve percorrer todo o caminho entre os componentes em que você confia. Uma borda que normaliza corretamente perde esse valor no momento em que um salto não protegido mais adiante permite que outra pessoa edite a afirmação enquanto ela viaja.

Trate deliberadamente cadeias com vários saltos

Vários proxies exigem um modelo de cadeia explícito. Não pegue o valor mais à esquerda ou mais à direita separado por vírgulas porque algum artigo de blog fez isso; descubra qual dos seus proxies acrescenta, qual substitui e qual preserva o campo de entrada. O NGINX, por exemplo, pode percorrer a lista de trás para frente contra seu conjunto confiável e parar no primeiro endereço que não possui, e essa é a regra desse produto, não uma lei que todo framework siga. Leia a documentação do seu próprio proxy com as mesmas duas perguntas: qual valor ele seleciona e em quais remetentes acredita?

Escreva a cadeia: ordem dos saltos, qual salto define o campo e qual salto remove as cópias de entrada. Depois mantenha essa nota ao lado da configuração do proxy, não apenas no chamado. Em seguida, teste enviando uma requisição com um cabeçalho forjado pelo processo de validação aprovado e confirmando que a origem a ignora.

Quando você adiciona um salto, revise esse documento. Um novo balanceador de carga inserido diante do proxy confiável pode mudar qual endereço vence sem que ninguém edite a aplicação.

Mantenha as duas observações no log

Onde o diagnóstico é autorizado, registre o par da conexão e o endereço de cliente normalizado como dois campos separados, e acrescente apenas os metadados de encaminhamento de que o propósito realmente precisa. Depois comprove a implantação com duas requisições: uma pelo proxy, que deveria registrar os dois valores de forma sensata, e uma tentativa direta à origem que deve ser recusada.

Lembre o que o par significa. O cabeçalho acrescenta contexto fornecido por um componente em que você escolheu confiar; o par continua sendo o único endereço que seu host realmente viu. Nenhum dos dois é prova de identidade individual, e um projeto que trate qualquer um deles como prova estará errado sobre alguém.

Artigos relacionados