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
?
HTTP_CLIENT_IP is the most reliable way of getting the user's IP address. Next is HTTP_X_FORWARDED_FOR, followed by REMOTE_ADDR. Check all three, in that order, assuming that the first one that is set (
isset($_SERVER['HTTP_CLIENT_IP'])
returns true if that variable is set) is correct. You can independently check if the user is using a proxy using various methods. Check this out.If you use it in a database, this is a good way:
Set the ip field in database to varchar(250), and then use this:
Then you just check $realip against the database ip field
You can use this function to get proper client IP:
You can also solve this problem via Apache configuration using mod_remoteip, by adding the following to a conf.d file:
I like Hrishikesh's answer, to which I only have this to add...because we saw a comma-delimited string coming across when multiple proxies along the way were used, we found it necessary to add an explode and grab the final value, like this:
the array_filter is in there to remove empty entries.
In the light of the latest httpoxy vulnerabilities, there is really a need for a full example, how to use
HTTP_X_FORWARDED_FOR
properly.So here is an example written in PHP, how to detect a client IP address, if you know that client may be behind a proxy and you know this proxy can be trusted. If you don't known any trusted proxies, just use
REMOTE_ADDR