php - remote_addr - server_addr
¿Cómo usar HTTP_X_FORWARDED_FOR correctamente? (6)
A la luz de las últimas vulnerabilidades de httpoxy , realmente se necesita un ejemplo completo, cómo usar HTTP_X_FORWARDED_FOR
correctamente.
Así que aquí hay un ejemplo escrito en PHP, cómo detectar la dirección IP de un cliente, si sabe que ese cliente puede estar detrás de un proxy y sabe que este proxy puede ser confiable. Si no conoces ningún proxy de confianza, solo usa 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 ();
?>
Muy bien, tengo un pequeño problema de autenticación. Mi servicio web 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.
Esto significa que el $_SERVER[''REMOTE_ADDR'']
puede ser incorrecto. Ya sé que nunca se puede confiar en ninguna información de IP; tengo la restricción solo en un intento de agregar otra capa de seguridad.
Si este es el resumen 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 la IP real del cliente como HTTP_X_FORWARDED_FOR
.
Para superar esto, mi servicio web tiene una lista de direcciones IP ''proxy de confianza'' y si REMOTE_ADDR
es de una de esas direcciones IP de confianza, entonces le dice a 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 (con bastante frecuencia) mySERVER obtiene el valor HTTP_X_FORWARDED_FOR
que tiene varias direcciones IP. De acuerdo con la documentación de 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 todas las demás direcciones IP son la de un proxy.
Entonces, si HTTP_X_FORWARDED_FOR
tiene múltiples valores y mi servicio está restringido por IP, ¿tengo que verificar el valor ''último'' de HTTP_X_FORWARDED_FOR
con mi lista de 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 en la lista blanca debe ser la de un proxy y no una IP que esté detrás del proxy (ya que podría ser una IP de host local y cambiar con frecuencia) .
¿Y qué hay de HTTP_CLIENT_IP
?
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, asumiendo que el primero que se establece ( isset($_SERVER[''HTTP_CLIENT_IP''])
devuelve true si esa variable está establecida) es correcta. Puede verificar de forma independiente si el usuario está utilizando un proxy utilizando varios métodos. Mira this
Me gusta la respuesta de Hrishikesh, a la que solo tengo que agregar esto ... porque vimos una cadena delimitada por comas cuando se utilizaron varios proxies en el camino, encontramos que era necesario agregar una explosión y capturar el valor final, como esta:
$IParray=array_values(array_filter(explode('','',$_SERVER[''HTTP_X_FORWARDED_FOR''])));
return end($IParray);
el array_filter está allí para eliminar las entradas vacías.
Puede utilizar esta función para obtener la IP del cliente adecuada:
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 '''';
}
Si lo usas en una base de datos, esta es una buena manera:
Establezca el campo ip en la base de datos en varchar (250) y luego use 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);
Luego, simplemente verifica $ realip contra el campo ip de la base de datos
También puede resolver este problema a través de la configuración de Apache usando mod_remoteip , agregando 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