2012-07-12 13 views
20

OK, ho un piccolo problema di autenticazione. Il mio servizio Web consente di connettersi alla mia API su HTTP con un nome utente e una password, ma questa connessione può anche essere limitata a uno specifico indirizzo IP.Come utilizzare correttamente HTTP_X_FORWARDED_FOR?

Ciò significa che il $_SERVER['REMOTE_ADDR'] può non essere corretto. So già che qualsiasi informazione IP non può mai essere veramente invocata - ho la restrizione solo nel tentativo di aggiungere un altro livello di sicurezza.

Se questo è il quadro generale di una richiesta al mio server web:

clientSERVER => clientPROXY => myPROXY => mySERVER

allora questo significa che mioserver mostra REMOTE_ADDR di myproxy invece di quella del client e invia l'attuale IP del client come HTTP_X_FORWARDED_FOR.

Per ovviare a questo, il mio servizio web ha una lista di indirizzi IP 'di proxy supporta' e se REMOTE_ADDR da uno di quegli indirizzi IP di fiducia, allora dice il mio servizio web che l'indirizzo IP effettivo è il valore di HTTP_X_FORWARDED_FOR.

Ora il problema è con clientPROXY. Ciò significa che (molto spesso) mySERVER assume il valore HTTP_X_FORWARDED_FOR che ha più indirizzi IP. In base alla documentazione HTTP_X_FORWARDED_FOR, il valore è un elenco separato da virgole di indirizzi IP in cui il primo IP è quello del vero client effettivo e ogni altro indirizzo IP è quello di un proxy.

Quindi, se HTTP_X_FORWARDED_FOR ha più valori e il mio servizio è IP limitato, devo controllare l'ultimo valore di HTTP_X_FORWARDED_FOR contro il mio elenco IP consentito e semplicemente ignorare l'IP del client attuale?

Suppongo che in un sistema, in cui devo impostare l'elenco di indirizzi IP consentiti, l'indirizzo IP autorizzato dovrebbe essere quello di un proxy e non un IP che si trova dietro il proxy (dal momento che potrebbe essere un IP localhost e cambiare frequentemente).

E che dire di HTTP_CLIENT_IP?

+0

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

risposta

-4

HTTP_CLIENT_IP è il modo più affidabile per ottenere l'indirizzo IP dell'utente. Il prossimo è HTTP_X_FORWARDED_FOR, seguito da REMOTE_ADDR. Controllare tutti e tre, in questo ordine, assumendo che il primo impostato (isset($_SERVER['HTTP_CLIENT_IP']) restituisce true se la variabile è impostata) sia corretto. Puoi verificare in modo indipendente se l'utente sta usando un proxy usando vari metodi. Controllare this out.

+7

Nessuno di questi header è "più affidabile" degli altri. Possono essere tutti forgiati dal cliente e le tue applicazioni devono sapere cosa è affidabile e cosa non lo è: di solito conosci la tua infrastruttura e l'indirizzo IP di qualsiasi proxy/bilanciamento del carico di fronte ai tuoi server HTTP. – Benjamin

+1

Vero, ma in generale, se si deve stabilire un ordine di preferenza basato sull'affidabilità presunta, è proprio questo. Mi rendo conto che possono essere manipolati tutti, ma se questi devono essere usati, questo è come farlo. – TheEnvironmentalist

+5

Perché c'è così tanta disinformazione su questo argomento? '$ _SERVER ['REMOTE_ADDR']' è il * solo * campo affidabile che non è influenzato dall'utente remoto, tutti gli altri sono analizzati dalle intestazioni. – transistor09

13

È possibile utilizzare questa funzione per ottenere il corretto IP client:

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

Questa risposta non affronta la situazione specifica descritta nella domanda, dove ** non tutte le richieste sono passate attraverso un proxy **. Di conseguenza, le richieste ricevute direttamente dai client potrebbero contenere indirizzi IP inaccurati nelle intestazioni. – duskwuff

+0

Bella risposta, puoi trovare anche accurata dalla classe Strumenti di Prestashop :). Trova la funzione getRemoteAddr() –

13

mi piace la risposta di Hrishikesh, a cui ho solo questo da aggiungere ... perché abbiamo visto una stringa delimitata da virgole imbattersi quando più proxy lungo il percorso sono stati usati, abbiamo trovato necessario aggiungere un esplodere e afferrare il valore finale, in questo modo:

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

l'array_filter è lì per rimuovere le voci vuote.

+2

Nota che sembra che l'utilizzo dell'ultimo valore nell'elenco stia probabilmente utilizzando l'IP di un proxy. Secondo il link sottostante, il client di origine è il primo IP. http://en.wikipedia.org/wiki/X-Forwarded-Per –

+2

Si noti inoltre che la stessa fonte dice che è facile da falsificare, quindi l'ultimo è più affidabile. Quindi ogni caso d'uso può fare scelte diverse. Se il caso d'uso per ottenere l'IP è la lotta contro la frode o lo spam, il primo IP potrebbe essere privo di significato e l'indirizzo più affidabile - l'ultimo - è molto utile. Se il caso d'uso per ottenere l'IP è un'attività meno nefasta, la prima sarebbe più utile. –

0

Se lo si utilizza in un database, questo è un buon modo:

Impostare il campo ip nel database di varchar (250), e quindi utilizzare questo:

$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); 

Poi basta controllare $ rea a contro il campo IP del database

6

Alla luce delle ultime vulnerabilità httpoxy, è davvero necessario un esempio completo, come utilizzare correttamente HTTP_X_FORWARDED_FOR.

Quindi, ecco un esempio scritto in PHP, come rilevare un indirizzo IP del client, se si sa che il client potrebbe essere dietro un proxy e si sa che questo proxy può essere considerato affidabile. Se non noto alcun proxy di fiducia, basta usare 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

Questa è una risposta eccellente, ma c'è un piccolo problema. Se la segnalazione di errori severi è attiva, provare a "tagliare (end (explode()))" su una riga restituirà "Solo le variabili devono essere passate per riferimento". Per ovviare a questo, imposta prima l'intestazione del proxy esploso su una variabile, quindi su "assetto (fine())". –

+0

@BenDyer Grazie, risolto. –

1

È inoltre possibile risolvere questo problema tramite configurazione di Apache utilizzando mod_remoteip, aggiungendo quanto segue in un file 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 
Problemi correlati