2012-07-12 13 views
20

Muy bien, tengo un pequeño problema de autenticación. Mi servicio web me permite conectarme a mi API a través de HTTP con un nombre de usuario y contraseña, pero esta conexión también puede restringirse a una dirección IP específica.¿Cómo se usa HTTP_X_FORWARDED_FOR correctamente?

Esto significa que el $_SERVER['REMOTE_ADDR'] puede ser incorrecto. Ya sé que cualquier información de IP nunca puede confiarse realmente. Tengo la restricción solo en un intento de agregar otra capa de seguridad.

Si este es el panorama general de una solicitud a mi servidor web:

clientSERVER => clientPROXY => myPROXY => mySERVER

entonces esto significa que Myserver muestra REMOTE_ADDR de myproxy en lugar de la del cliente y envía el actual IP del cliente como HTTP_X_FORWARDED_FOR.

Para superar esto, mi servicio web tiene una lista de direcciones IP 'de confianza de proxy' y si REMOTE_ADDR es de una de esas direcciones IP de confianza, entonces se dice que mi servicio web que la dirección IP real es el valor de HTTP_X_FORWARDED_FOR.

Ahora el problema es con clientPROXY. Esto significa que (muy a menudo) mySERVER obtiene HTTP_X_FORWARDED_FOR valor que tiene múltiples direcciones IP. De acuerdo con la documentación HTTP_X_FORWARDED_FOR, el valor es una lista de direcciones IP separadas por comas, donde la primera IP es la del verdadero cliente real y cualquier otra dirección IP es la de un proxy.

lo tanto, si HTTP_X_FORWARDED_FOR tiene múltiples valores y mi servicio está restringido IP, tengo que comprobar el 'último' valor de HTTP_X_FORWARDED_FOR contra mi lista de direcciones IP permitidas y simplemente ignorar la IP del cliente real?

Supongo que en un sistema, donde tengo que configurar la lista de direcciones IP permitidas, la dirección IP incluida debe ser la de un proxy y no una IP que está detrás del proxy (ya que podría ser una IP localhost) y cambiar frecuentemente).

¿Y qué de HTTP_CLIENT_IP?

+0

http : //stackoverflow.com/q/7445592/759866 – Benjamin

Respuesta

-4

HTTP_CLIENT_IP es la forma más confiable de obtener la dirección IP del usuario. El siguiente es HTTP_X_FORWARDED_FOR, seguido de REMOTE_ADDR. Verifique los tres, en ese orden, suponiendo que el primero que está configurado (isset($_SERVER['HTTP_CLIENT_IP']) devuelve verdadero si esa variable está configurada) es correcto. Puede verificar independientemente si el usuario está usando un proxy usando varios métodos. Compruebe this hacia fuera.

+7

Ninguno de estos encabezados es "más confiable" que los otros. Todos pueden ser falsificados por el cliente, y sus aplicaciones necesitan saber qué es lo que se confía y qué no: normalmente se conoce su infraestructura y la dirección IP de cualquier proxy/equilibrador de carga frente a su (s) servidor (es) HTTP. – Benjamin

+1

Es cierto, pero en general, si se va a establecer un orden de preferencia basado en la fiabilidad asumida, esto es todo. Me doy cuenta de que todos pueden ser manipulados, pero si deben usarse, así es como hacerlo. – TheEnvironmentalist

+5

¿Por qué hay tanta desinformación sobre este tema? '$ _SERVER ['REMOTE_ADDR']' es el campo * solo * confiable que no está influenciado por el usuario remoto, todos los demás se analizan desde los encabezados. – transistor09

13

Puede utilizar esta función para obtener adecuado IP del cliente:

public function getClientIP(){  
    if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)){ 
      return $_SERVER["HTTP_X_FORWARDED_FOR"]; 
    }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { 
      return $_SERVER["REMOTE_ADDR"]; 
    }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { 
      return $_SERVER["HTTP_CLIENT_IP"]; 
    } 

    return ''; 
} 
+3

Esta respuesta no aborda la situación específica descrita en la pregunta, donde ** no todas las solicitudes se pasan a través de un proxy **. Como resultado, las solicitudes recibidas directamente de los clientes pueden contener direcciones IP inexactas en los encabezados. – duskwuff

+0

Buena respuesta, puede encontrar incluso precisa de la clase de herramientas de Prestashop :). Busque la función getRemoteAddr() –

13

me gusta la respuesta de Hrishikesh, a la que sólo tengo esto para añadir ... porque vimos una cadena delimitada por comas cuando viene a través de múltiples se utilizaron los proxies lo largo del camino, encontramos que es necesario añadir un explotan y agarrar el valor final, así:

$IParray=array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']))); 
return end($IParray); 

la array_filter está ahí para eliminar las entradas vacías.

+2

Tenga en cuenta que parece que el uso del último valor en la lista aún probablemente utiliza la IP de un proxy. De acuerdo con el siguiente enlace, el cliente de origen es el PRIMERO IP. http://en.wikipedia.org/wiki/X-Forwarded-For –

+2

También tenga en cuenta que la misma fuente dice que esto es fácil de falsificar, por lo que el último es más confiable. Entonces, cada caso de uso puede tomar diferentes decisiones. Si el caso de uso para obtener el IP está combatiendo el fraude o el correo no deseado, el primer IP puede carecer de sentido y la dirección más confiable, la última, es la más útil. Si el caso de uso para obtener el IP es actividades menos nefastas, el primero sería el más útil. –

0

Si lo usa en una base de datos, esta es una buena manera:

Configure el campo IP en la base de datos a varchar (250), y luego utilice esto:

$theip = $_SERVER["REMOTE_ADDR"]; 

if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) { 
    $theip .= '('.$_SERVER["HTTP_X_FORWARDED_FOR"].')'; 
} 

if (!empty($_SERVER["HTTP_CLIENT_IP"])) { 
    $theip .= '('.$_SERVER["HTTP_CLIENT_IP"].')'; 
} 

$realip = substr($theip, 0, 250); 

A continuación, sólo comprobar $ realip contra el campo de la base de datos ip

6

A la luz de las últimas vulnerabilidades httpoxy, existe realmente la necesidad de un ejemplo completo, cómo usar HTTP_X_FORWARDED_FOR correctamente.

Aquí hay un ejemplo escrito en PHP, cómo detectar una dirección IP del cliente, si sabe que ese cliente puede estar detrás de un proxy y usted sabe que este proxy puede ser de confianza. Si no conoce los proxies de confianza, sólo tiene que utilizar REMOTE_ADDR

<?php 

function get_client_ip() 
{ 
    // Nothing to do without any reliable information 
    if (!isset ($_SERVER['REMOTE_ADDR'])) { 
     return NULL; 
    } 

    // Header that is used by the trusted proxy to refer to 
    // the original IP 
    $proxy_header = "HTTP_X_FORWARDED_FOR"; 

    // List of all the proxies that are known to handle 'proxy_header' 
    // in known, safe manner 
    $trusted_proxies = array ("2001:db8::1", "192.168.50.1"); 

    if (in_array ($_SERVER['REMOTE_ADDR'], $trusted_proxies)) { 

     // Get the IP address of the client behind trusted proxy 
     if (array_key_exists ($proxy_header, $_SERVER)) { 

      // Header can contain multiple IP-s of proxies that are passed through. 
      // Only the IP added by the last proxy (last IP in the list) can be trusted. 
      $proxy_list = explode (",", $_SERVER[$proxy_header]); 
      $client_ip = trim (end ($proxy_list)); 

      // Validate just in case 
      if (filter_var ($client_ip, FILTER_VALIDATE_IP)) { 
       return $client_ip; 
      } else { 
       // Validation failed - beat the guy who configured the proxy or 
       // the guy who created the trusted proxy list? 
       // TODO: some error handling to notify about the need of punishment 
      } 
     } 
    } 

    // In all other cases, REMOTE_ADDR is the ONLY IP we can trust. 
    return $_SERVER['REMOTE_ADDR']; 
} 

print get_client_ip(); 

?> 
+0

Esta es una respuesta excelente, pero hay un problema menor. Si el informe de error estricto está activado, tratar de 'recortar (end (explotar()))' en una línea devolverá "Solo las variables se deben pasar por referencia". Para evitar eso, primero establezca el encabezado del proxy explotado en una variable, luego 'trim (end())' en su lugar. –

+0

@BenDyer Gracias, lo arreglaron. –

1

También puede resolver este problema a través de la configuración de Apache usando mod_remoteip, añadiendo lo siguiente a un archivo conf.d.:

RemoteIPHeader X-Forwarded-For 
RemoteIPInternalProxy 172.16.0.0/12 
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined