Quantcast



Docs


Blogs


Forums


Samples


Media


Labs


Resources

 




DevCentral > Weblogs > Lori MacVittie - Two Different Socks
 Using "X-Forwarded-For" in Apache or PHP
posted on Monday, June 02, 2008 4:20 AM

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




Email This
  del.icio.us
      

Feedback


6/4/2008 2:53 AM
Gravatar My fast solution for logging in the same apache-log even if the header X-Forwarder-For not exist.

LogFormat "%{X-Forwarder-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" f5_forwarder
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

SetEnvIf X-Forwarder-For "^.*\..*\..*\..*" is-forwarder

CustomLog logs/access_log combined env=!is-forwarder
CustomLog logs/access_log f5_forwarder env=is-forwarder
Robert

6/10/2008 7:19 AM
Gravatar How safe is it to rely on the IP address captured from X_FORWARDED_FOR HTTP Header for IP-based access restriction?
Venkatesh Kanchan

6/10/2008 7:24 AM
Gravatar 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
Lori MacVittie

6/18/2008 7:13 AM
Gravatar I have the same issue. But my webserver only allow https. How can I enable this setting in F5? I cannot apply http profile in this case.
Edwin

6/18/2008 11:11 AM
Gravatar 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
Lori MacVittie

7/22/2008 6:49 PM
Gravatar Venkatesh Kanchan,

If you're going to use the client IP address LTM receives on the TCP connection as a means to authenticate clients, you should remove all existing XFF headers and then insert a new one using an iRule. This should be considered very secure, as you're not accepting any client side input and instead depending on the actual client IP LTM sees.

when HTTP_REQUEST {
# Remove all existing XFF headers
while {[HTTP::header exists "X-Forwarded-For"}{
HTTP::header remove "X-Forwarded-For"
}
# Insert a new XFF header with the client IP
HTTP::header insert "X-Forwarded-For" [IP::client_addr]
}

Aaron
Aaron

8/22/2008 7:24 AM
Gravatar X-Forwarded-For
 Leave Feedback
Title  
Name  
Email
Url
Comments   
Please add 6 and 8 and type the answer here: