nginx real_ip_header y X-Fordered-For parece incorrecto

59

La descripción de Wikipedia del encabezado HTTP X-Forwarded-Fores:

X-Forward-For: cliente1, proxy1, proxy2, ...

La documentación de nginx para la directiva real_ip_headerlee, en parte:

Esta directiva establece el nombre del encabezado utilizado para transferir la dirección IP de reemplazo.
En el caso de X-Fordered-For, este módulo utiliza la última ip en el encabezado X-Fordered-For para el reemplazo. [El énfasis es mío]

Estas dos descripciones parecen estar en desacuerdo entre sí. En nuestro escenario, el X-Forwarded-Forencabezado es exactamente como se describe: la dirección IP "real" del cliente es la entrada más a la izquierda. Del mismo modo, el comportamiento de nginx es utilizar el valor más adecuado , que, obviamente, es solo uno de nuestros servidores proxy.

Según tengo entendido X-Real-IP, se supone que debe usarse para determinar la dirección IP del cliente real , no el proxy. ¿Me estoy perdiendo algo o es un error en nginx?

Y, más allá de eso, ¿alguien tiene alguna sugerencia sobre cómo hacer que el X-Real-IPencabezado muestre el valor más a la izquierda , como lo indica la definición de X-Forwarded-For?

Kirk Woll
fuente

Respuestas:

97

Creo que la clave para resolver los problemas de X-Fordered-For cuando se encadenan varias IP es la opción de configuración introducida recientemente real_ip_recursive(agregada en nginx 1.2.1 y 1.3.0). De los documentos nginx realip :

Si la búsqueda recursiva está habilitada, una dirección de cliente original que coincide con una de las direcciones confiables se reemplaza por la última dirección no confiable enviada en el campo de encabezado de solicitud.

nginx estaba tomando la última dirección IP en la cadena por defecto porque esa era la única en la que se suponía que era de confianza. Pero con la nueva real_ip_recursivehabilitada y con múltiples set_real_ip_fromopciones, puede definir múltiples proxies confiables y obtendrá la última IP no confiable.

Por ejemplo, con esta configuración:

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;

Y un encabezado X-Fordered-For que resulta en:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx ahora seleccionará 123.123.123.123 como la dirección IP del cliente.

En cuanto a por qué nginx no solo elige la dirección IP más a la izquierda y requiere que defina explícitamente servidores proxy confiables, es para evitar la suplantación de IP fácil.

Digamos que la dirección IP real de un cliente es 123.123.123.123. Digamos también que el cliente no es bueno, y están tratando de falsificar su dirección IP 11.11.11.11. Envían una solicitud al servidor con este encabezado ya en su lugar:

X-Forwarded-For: 11.11.11.11

Dado que los proxys inversos simplemente agregan IP a esta cadena X-Fordered-For, digamos que termina luciendo así cuando nginx llega a ella:

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

Si simplemente toma la dirección más a la izquierda, eso le permitiría al cliente falsificar fácilmente su dirección IP. Pero con el ejemplo anterior nginx config, nginx solo confiará en las dos últimas direcciones como proxies. Esto significa que nginx elegirá correctamente 123.123.123.123como la dirección IP, a pesar de que la IP falsificada es realmente la más a la izquierda.

Nick M
fuente
2
Muchas gracias por esto, realmente me ayudó. Esta debería ser la respuesta aceptada.
José F. Romaniello
1
Por defecto, real_ip_header parece ser X-Real-IP de acuerdo con nginx.org/en/docs/http/ngx_http_realip_module.html ¿Significa que un usuario malintencionado puede enviar una solicitud con X-Real-IP aleatorio y que se usará como $ remote_addr en nginx (y posiblemente también pasó a la aplicación)?
Gansbrest
@gansbrest No, porque set_real_ip_from limita los hosts de confianza.
El Yobo
9

El análisis del X-Forwarded-Forencabezado es realmente defectuoso en el 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;
  }
}

Comienza en el extremo derecho de la cadena del encabezado, y tan pronto como ve un espacio o una coma, deja de buscar y pega la parte a la derecha del espacio o la coma en la variable IP. Por lo tanto, trata la dirección proxy más reciente como la dirección del cliente original .

No está jugando bien según las especificaciones; Este es el peligro de no explicarlo en términos dolorosamente obvios en un RFC.

Aparte: es difícil incluso encontrar una buena fuente primaria en el formato, que fue originalmente definido por Squid: una excavación en su documentación confirma el pedido; el más a la izquierda es el cliente original, el más a la derecha es el anexo más reciente. Estoy muy tentado a agregar una [cita requerida] a esa página de wikipedia. Una edición anónima parece ser la autoridad de Internet sobre el tema.

Si es posible, ¿puede hacer que sus proxies intermedios dejen de agregarse al final del encabezado, dejándolo solo con la dirección real del cliente?

Shane Madden
fuente
Gracias por la respuesta, @Shane. De hecho, al llegar a nginx, X-Forwarded-Forya existe un. (es la dirección IP correcta del cliente) nginx se agrega la dirección IP de nuestro equilibrador de carga (el salto anterior) al X-Forwarded-Forencabezado. (presumiblemente agregando lo que ve como la "dirección remota") Si simplemente no hiciera eso, podría usar el X-Forwarded-Forencabezado como antes. (recientemente hemos estado migrando a nginx)
Kirk Woll
@Kirk Entonces, cuando nginx obtiene el encabezado, ¿es solo la dirección del cliente original? Pero cuando lo procesa, ¿se agrega en el encabezado del servidor proxy de conexión? Eso no cuadra, la única vez que debe tocar ese encabezado es cuando envía la conexión a otro proxy a través de un proxy_pass- e incluso entonces, solo cuando está proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;en su lugar.
Shane Madden
Incluso el W3C se equivoca : su documentación indica que "los servidores proxy deben agregar la dirección IP del iniciador de la solicitud al final de una lista separada por comas en un campo de encabezado HTTP X-Fordered-For", debería indicar el comienzo .
Ian Kemp
3
@IanKemp, no, el final es correcto. Para el lado del servidor de un proxy, el iniciador de la solicitud (es decir, la solicitud de TCP ) es el proxy anterior (si hay uno). Ese proxy anterior posiblemente ya envíe un X-Forwarded-Forencabezado con posiblemente la dirección del cliente original a la izquierda y posiblemente cualquier proxy anterior adjunto a eso. Por lo tanto, el proxy actualmente en servicio agregaría el proxy anterior (= iniciador) al final de esa lista y serviría el X-Forwarded-Forencabezado así aumentado al siguiente salto ascendente. Por supuesto, podrían haber elegido una redacción más obvia.
blubberdiblub
5

X-Real-IP es la dirección IP del cliente real con el que está hablando el servidor (el cliente "real" del servidor), que, en el caso de una conexión proxy, es el servidor proxy. Es por eso que X-Real-IP contendrá la última IP en el encabezado X-Fordered-For.

usuario558061
fuente
1
OK, pero, para mí, eso simplemente nunca es información útil. Quiero obtener la dirección IP original del cliente, eso es crucial y, de acuerdo con todo lo que he leído, el propósito de estos encabezados. ¿Por qué querría saber la dirección IP de nuestros servidores proxy?
Kirk Woll
Si no es útil para ti, entonces no es para ti. Nadie te obliga a usar X-Real-IP. Si necesita la IP del usuario en su aplicación, haga que su aplicación analice X-Fordered-For (que no siempre es confiable porque hay algunos proxies (dispositivos de seguridad de Internet / firewalls) que no configuran X-Forward- Por). En el contexto de nginx, X-Forward-For no es importante porque de todos modos no está hablando con esos clientes, aparte de la última entrada (X-Real-IP) que es el cliente de nginx. Si no lo necesita, no lo configure, desarme o simplemente
ignórelo
2
No, lo que quiero decir es, ¿por qué X-Real-IPregresaba dirección IP de mi propio servidor proxy cada vez sea útil?
Kirk Woll
Genial ... responde hombre. Estaba buscando esta información precisa. Necesito hablar con un servidor ncat en mi servidor proxy, así que necesito esto sobre la marcha.
Yugal Jindle