How to use HTTP_X_FORWARDED_FOR properly?

kingmaple picture kingmaple · Jul 12, 2012 · Viewed 108.6k times · Source

Alright, I have an small authentication issue. My web service allows to connect to my API over HTTP with a username and password, but this connection can also be restricted to a specific IP address.

This means that the $_SERVER['REMOTE_ADDR'] can be incorrect. I already know that any IP information can never truly be relied upon - I have the restriction only in an attempt to add another layer of security.

If this is the general overview of a request to my web server:

clientSERVER => clientPROXY => myPROXY => mySERVER

Then this means that mySERVER shows REMOTE_ADDR of myPROXY instead of that of the client and sends the actual IP of the client as HTTP_X_FORWARDED_FOR.

To overcome this, my web service has a list of 'trusted proxy' IP addresses and if REMOTE_ADDR is from one of those trusted IP addresses, then it tells my web service that the actual IP address is the value of HTTP_X_FORWARDED_FOR.

Now the problem is with clientPROXY. This means that (quite often) mySERVER gets HTTP_X_FORWARDED_FOR value that has multiple IP addresses. According to HTTP_X_FORWARDED_FOR documentation, the value is a comma-separated list of IP addresses where the first IP is that of the actual true client and every other IP address is that of a proxy.

So, if HTTP_X_FORWARDED_FOR has multiple values and my service is IP restricted, do I have to check the 'last' value of HTTP_X_FORWARDED_FOR against my allowed IP list and just ignore the actual client IP?

I assume that in a system, where I have to set the list of allowed IP addresses, the whitelisted IP address should be that of a proxy and not an IP that is behind the proxy (since that could be some localhost IP and change frequently).

And what of HTTP_CLIENT_IP?

Answer

Hrishikesh Mishra picture Hrishikesh Mishra · May 13, 2014

You can use this function to get proper client IP:

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 '';
}