Using "X-Forwarded-For" in Apache or PHP

An issue that often comes up for users of any full proxy-based product is that the original client IP address is often lost to the application or web server. This is because in a full proxy system there are two connections; one between the client and the proxy, and a second one between the proxy and the web server. Essentially, the web server sees the connection as coming from the proxy, not the client. 

Needless to say, this can cause problems if you want to know the IP address of the real client for logging, for troubleshooting, for tracking down bad guys, or performing IP address specific tasks such as geocoding. Maybe you're just like me and you're nosy, or you're like Don and you want the webalizer graphs to be a bit more interesting (just one host does not a cool traffic graph make, after all!).

That's where the "X-Forwarded-For" HTTP header comes into play. Essentially the proxy can, if configured to do so, insert the original client IP address into a custom HTTP header so it can be retrieved by the server for processing.

If you've got a BIG-IP you can simply enable the ability to insert the "X-Forwarded-For" header in the http profile. Check out the screen shot below to see just how easy it is. Yeah, it's that easy.

If for some reason you can't enable this feature in the HTTP profile, you can write an iRule to do the same thing.

when HTTP_REQUEST { HTTP::header insert "X-Forwarded-For" [IP::client_addr]}

Yeah, that's pretty easy, too. So now that you're passing the value along, what do you do with it?

Modifying Apache's Log Format

Well, Joe has a post describing how to obtain this value in IIS. But that doesn't really help if you're not running IIS and like me have chosen to run a little web server you may have heard of called Apache.

Configuring Apache to use the X-Forwarded-For instead of (or in conjunction with) the normal HTTP client header is pretty simple. ApacheWeek has a great article on how to incorporate custom fields into a log file, but here's the down and dirty. Open your configuration file (usually in /etc/httpd/conf/) and find the section describing the log formats. Then add the following to the log format you want to modify, or create a new one that includes this to extract the X-Forwarded-For value:

    %{X-Forwarded-For}i

That's it. If you don't care about the proxy IP address, you can simply replace the traditional %h in the common log format with the new value, or you can add it as an additional header. Restart Apache and you're ready to go.

Getting the X-Forwarded-For from PHP

If you're like me, you might have written an application or site in PHP and for some reason you want the real client IP address, not the proxy IP address. Even though my BIG-IP has the X-Forwarded-For functionality enabled in the http profile, I still need to access that value from my code so I can store it in the database.

$headers = apache_request_headers(); $real_client_ip = $headers["X-Forwarded-For"];

That's it, now I have the real IP address of the client, and not just the proxy's address.

Happy Coding & Configuring!

Imbibing: Coffee

Published Jun 02, 2008
Version 1.0

Was this article helpful?

8 Comments

  • The IP address in the HTTP header will only be as reliable as the source. If the BIG-IP (or proxy) is talking directly to the client, the IP address captured is reliable. If you aren't sure about the source of the request - i.e. the client might be accessing the service through a different proxy first, then you can't be certain that the address forwarded is the correct one.

     

     

    Basically, if the communication is directly between the client and the BIG-IP (assuming your firewall isn't reverse NAT'ing incoming connections) then it's safe to rely on it.

     

     

    Lori

     

  • Hi Edwin,

     

     

    I asked the DevCentral team about this one and the answer is that if you're terminating SSL on the BIG-IP you can use the HTTP profile. But if you aren't terminating it, i.e. you're just letting it pass through, then you won't be able to insert the XFF.

     

     

    Lori
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    You should only be seeing one IP in the logs. If you're seeing two it's likely because you have a header being inserted with the original address that apache is pulling out and logging, but you're still logging the actual source from the proxy as well. Have you checked your conf settings?

     

     

    From what I've seen, BIG-IP doesn't pass two addresses. ;)

     

     

    Colin
  • @Pete

     

     

    Hmmm...I'm not an expert in the Apache mod_X configurations, but I would think that between mod_security and mod_rewrite that you could restrict access based on an just about any HTTP header in the configuration without requiring any code (SHTML, PHP, etc...).

     

     

    I know you can certainly do that with an iRule, it's pretty simple stuff to base access on an HTTP header value so I'm guessing the same is true of mod_rewrite/mod_security.

     

     

    Lori
  • @jwang

     

     

    Other than the mentioned change to the httpd.conf - and a restart - there shouldn't be anything you need to do for Apache.

     

     

  • @JefferE

     

     

    Without knowing which method was used to get the IP address (or what generated it) I can't say for sure what the ",50" represents but it does not appear to be a netmask.

     

     

    Lori