What Jessie Did Next...

...being the inane ramblings of a mundane Yorkshire bird.

The sort of work I do is usually to do with end user services – websites which allow a user to create a login and password to give them access to larger featuresets, etc. You know the kind of thing – social network websites are a prime example: as part of that I frequently get asked to log information a user may do, recording the source IP address of any messages they may leave in order to protect from abuse.

A frequent mistake folks make in writing code to do this is in the IP address which made the HTTP request. Most larger ISPs enforce transparent proxying on the user, meaning that instead of having the IP address of the end user themselves you’ve got the IP address of a proxy which may handle hundreds of thousands of users! It causes issues not just in traceability, but also in things like bandwidth logging if you’re doing it at an application level.

Enter X-Forwarded-For. It’s an HTTP header which most proxy software will add, giving the source IP address which requested the page through the proxy and preventing proxy servers becoming anonymising services.

This is exposed to PHP through the $_SERVER superglobal, so you can use it like so:

if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
logEntry("User connected from ".$_SERVER['HTTP_X_FORWARDED_FOR']);
} else {
logEntry("User connected from ".$_SERVER['REMOTE_ADDR']);

Now there’s a gotcha here. A lot of ISPs such as AOL and NTL allocate ‘private’ RFC1918 IP space internal to their network. That means if you get or similar then you’re on a hide into nothing because you’ve not got the proxy which may be ‘seeing’ that address – so you need to log both when you find a proxy:

if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
logEntry("User connected via proxy ".$_SERVER['REMOTE_ADDR'].
} else {
logEntry("User connected from ".$_SERVER['REMOTE_ADDR']);

But what if users are stringing proxies together? Well, that’s dealt with too. The proxy software appends itself to each X-Forwarded-For header, separated by commas.

Of course this should be treat as a first line of defence – if someone’s really wanting to hide themselves they can, through IP spoofing or fiddling their own proxy software to remove the header. However, it’s a neat way of preventing false positives and – more importantly – finding out who’s really behind stuff, now RFC1918 endpoints are becoming more and more common.

Wikipedia has a bit about X-Forwarded-For here, if you fancy a little more reading.


  1. Good article 🙂

    I’d also like to add the fact that in my experience from a web services point of view, you must have a heightened level of paranoia about who or what is connecting to your service.

    At the end of the day, the internet is a free for all – you don’t know who or what is connecting to your site, so you must take steps to protect the service you have built. X_F_F contributes one part of a good logging policy and it will allow the administrators of a service to follow up any "anti social" attempts to disrupt your service (with the proper authorities).

    After all (unfortunately) – there are a lot of people out there with nothing better to do than try and disrupt/disturb/upset/destroy things 🙁

  2. btw – its "a hiding to nothing", as in "we were on a hiding to nothing" – not "hide into nothing".

    Think. "large score to nil".

Leave a Reply

Your email address will not be published.


This site uses Akismet to reduce spam. Learn how your comment data is processed.