nginx real_ip_header e X-Forwarded-For parece errado


59

A descrição da Wikipedia do cabeçalho HTTP X-Forwarded-Foré:

Encaminhado para X: cliente1, proxy1, proxy2, ...

A documentação nginx para a diretiva real_ip_headerdiz, em parte:

Esta diretiva define o nome do cabeçalho usado para transferir o endereço IP de substituição.
No caso de X-Forwarded-For, este módulo usa o último ip no cabeçalho X-Forwarded-For para substituição. [Ênfase minha]

Essas duas descrições parecem estar em desacordo. Em nosso cenário, o X-Forwarded-Forcabeçalho é exatamente como descrito - o endereço IP "real" do cliente é a entrada mais à esquerda. Da mesma forma, o comportamento do nginx é usar o valor mais à direita - que, obviamente, é apenas um de nossos servidores proxy.

Meu entendimento X-Real-IPé que ele deve ser usado para determinar o endereço IP real do cliente - não o proxy. Estou faltando alguma coisa, ou isso é um bug no nginx?

E, além disso, alguém tem alguma sugestão de como fazer com que o X-Real-IPcabeçalho exiba o valor mais à esquerda , conforme indicado pela definição de X-Forwarded-For?

Respostas:


97

Acredito que a chave para resolver problemas com o X-Forwarded-For quando vários IPs estão encadeados é a opção de configuração recentemente introduzida real_ip_recursive(adicionada no nginx 1.2.1 e 1.3.0). Nos documentos do nginx realip :

Se a pesquisa recursiva estiver ativada, um endereço de cliente original que corresponda a um dos endereços confiáveis ​​será substituído pelo último endereço não confiável enviado no campo de cabeçalho da solicitação.

O nginx estava pegando o último endereço IP da cadeia por padrão, porque esse era o único que era considerado confiável. Mas com o novo real_ip_recursiveativado e com várias set_real_ip_fromopções, você pode definir vários proxies confiáveis ​​e ele buscará o último IP não confiável.

Por exemplo, com esta configuração:

set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

E um cabeçalho X-Forwarded-For resultando em:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

O nginx agora selecionará 123.123.123.123 como o endereço IP do cliente.

Quanto ao motivo pelo qual o nginx não escolhe apenas o endereço IP mais à esquerda e exige que você defina explicitamente proxies confiáveis, é para impedir a falsificação fácil de IP.

Digamos que o endereço IP real de um cliente seja 123.123.123.123. Digamos também que o cliente não é bom, e eles estão tentando falsificar seu endereço IP 11.11.11.11. Eles enviam uma solicitação ao servidor com este cabeçalho já instalado:

X-Forwarded-For: 11.11.11.11

Como os proxies reversos simplesmente adicionam IPs a essa cadeia X-Forwarded-For, digamos que ele se parece com isso quando o nginx chega a ele:

X-Forwarded-For: 11.11.11.11, 123.123.123.123, 192.168.2.1, 127.0.0.1

Se você simplesmente pegasse o endereço mais à esquerda, isso permitiria que o cliente falsificasse facilmente seu endereço IP. Mas com o exemplo acima da configuração nginx, o nginx confiará apenas nos dois últimos endereços como proxies. Isso significa que o nginx escolherá corretamente 123.123.123.123o endereço IP, apesar de o IP falsificado ser o mais à esquerda.


2
Muito obrigado por isso, isso realmente me ajudou. Essa deve ser a resposta aceita.
— José F. Romaniello 26/12/2013

11
Por padrão, real_ip_header parece ser X-Real-IP de acordo com nginx.org/en/docs/http/ngx_http_realip_module.html Isso significa que um usuário mal-intencionado pode simplesmente enviar uma solicitação com X-Real-IP aleatório e que será usado como $ remote_addr no nginx (e também possivelmente passado para o aplicativo)?
— gansbrest

@gansbrest Não, porque set_real_ip_from limita os hosts confiáveis.
— El Yobo

9

A análise do X-Forwarded-Forcabeçalho é realmente falha no módulo nginx real_ip.

len = r->headers_in.x_forwarded_for->value.len;
ip = r->headers_in.x_forwarded_for->value.data;

for (p = ip + len - 1; p > ip; p--) {
  if (*p == ' ' || *p == ',') {
    p++;
    len -= p - ip;
    ip = p;
    break;
  }
}

Inicia na extremidade direita da cadeia de cabeçalho e, assim que vê um espaço ou vírgula, para de procurar e cola a parte à direita do espaço ou vírgula na variável IP. Portanto, trata o endereço de proxy mais recente como o endereço de cliente original .

Não está se saindo bem de acordo com as especificações; esse é o risco de não ser explicitado em termos dolorosamente óbvios em uma RFC.

Além disso: é difícil até encontrar uma boa fonte primária no formato, que foi originalmente definido pelo Squid - uma escavação na documentação confirma a ordem; mais à esquerda é o cliente original, mais à direita é o anexo mais recente. Estou extremamente tentado a adicionar uma [citação necessária] a essa página da Wikipedia. Uma edição anônima parece ser a autoridade da Internet sobre o assunto.

Se possível, você pode fazer com que seus proxies intermediários parem de se adicionar ao final do cabeçalho, deixando-o apenas com o endereço do cliente real?


Obrigado pela resposta, @ Shane. De fato, ao atingir o nginx, um X-Forwarded-Forjá existe. (é o endereço IP do cliente correto), o próprio nginx passa a acrescentar o endereço IP do nosso balanceador de carga (o salto anterior) ao X-Forwarded-Forcabeçalho. (presumivelmente anexando o que ele vê como "endereço remoto"). Se simplesmente não fizesse isso, seria capaz de usar o X-Forwarded-Forcabeçalho como antes. (temos sido recentemente migrando para nginx)
— Kirk Woll

@ Kirk Então, quando o nginx obtém o cabeçalho, é apenas o endereço do cliente original? Mas quando está processando, é adicionado no cabeçalho do servidor proxy de conexão? Isso não contribui - o único momento em que ele deve tocar nesse cabeçalho é quando está enviando a conexão para outro proxy por meio de um proxy_pass- e, mesmo assim, apenas proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;no local.
— Shane Madden

Até o W3C erra : a documentação indica "proxies devem adicionar o endereço IP do iniciador da solicitação ao final de uma lista separada por vírgulas em um campo de cabeçalho X-Forwarded-For HTTP", deve indicar o início .
— Ian Kemp

3
@IanKemp, não, o fim está correto. Para o lado do servidor de um proxy, o iniciador da solicitação (ou seja, solicitação TCP ) é o proxy anterior (se houver). Esse proxy anterior possivelmente já envia um X-Forwarded-Forcabeçalho com o endereço do cliente original à esquerda e possivelmente os proxies anexados a ele. Portanto, o proxy atualmente em exibição adiciona o proxy anterior (= iniciador) ao final dessa lista e serve o X-Forwarded-Forcabeçalho assim aumentado para o próximo salto upstream. É verdade que eles poderiam ter escolhido uma redação mais óbvia.
— precisa saber é o seguinte

5

X-Real-IP é o endereço IP do cliente real com o qual o servidor está falando (o cliente "real" do servidor), que, no caso de uma conexão com proxy, é o servidor proxy. É por isso que o X-Real-IP conterá o último IP no cabeçalho X-Forwarded-For.


11
OK, mas, para mim, isso simplesmente nunca é uma informação útil. Quero obter o endereço IP original do cliente - isso é crucial e, de acordo com tudo que li, o objetivo desses cabeçalhos. Por que eu gostaria de saber o endereço IP dos nossos servidores proxy?
— 22411 Kirk Woll

Se não é útil para você, então não é para você. Ninguém está forçando você a usar o X-Real-IP. Se você precisar do IP do usuário em seu aplicativo, faça com que ele analise o X-Forwarded-For (o que nem sempre é confiável, porque existem alguns proxies (dispositivo de segurança da Internet / firewalls) que não definem o X-Forwarded- Para). No contexto do nginx, o X-Forwarded-For não é importante porque não está falando com esses clientes, além da última entrada (o X-Real-IP), que é o cliente do nginx. Se você não precisar, não o defina, desative-o ou ignore-o: /
— user558061

2
Não, o que eu quero dizer é, por que X-Real-IPo retorno endereço IP do meu próprio servidor proxy sempre ser útil?
— 22411 Kirk Woll

Ótimo .. responda cara. Eu estava procurando por esta informação precisa. Preciso conversar com um servidor ncat no meu servidor proxy, por isso preciso disso rapidamente.
— Yugal Jindle
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.