PDA

View Full Version : getting client IP: getRemoteAddr() and Apache or Firewall's x-forwarded-for headers


kjkoster
26-07-2010, 19:53
Dear All,

We have discussed getRemoteAddr() and x-forwarded-for headers before (http://java-monitor.com/forum/showthread.php?t=361). Cyrille Le Clerc (http://www.slideshare.net/cyrille.leclerc) then posted how to deal with such headers properly. As of version 6.0.24 of Tomcat, Cyrille's code is part of the Tomcat server. It is not switched on by default, but that is quite simple to do.

Cyrille wrote a Tomcat valve that replaces the IP address that getRemoteAddr() would return and fills in the IP address of the actual HTTP client. Using the valve you can strip the x-forwarded-for handling code from your project. getRemoteAddr() now works as you would expect, regardless of whether there is a proxy or front-end web server present or not.

Configuring the remote IP valve (which implements correct x-forwarded-for handling) is briefly documented on the Tomcat valve reference (http://tomcat.apache.org/tomcat-7.0-doc/config/valve.html#Remote_IP_Valve) and more extensively on the remote IP valve's Google Code home page (http://code.google.com/p/xebia-france/wiki/RemoteIpValve).

Let's look at a typical setup: a system where we have a Tomcat server sitting behind an Apache httpd front-end. For simplicity, let's assume that the Apache server runs on the same machine as Tomcat does. In this situation, Tomcat will return 127.0.0.1 for all calls to getRemoteAddr(). While that is technically correct (the requesting Apache httpd process does run on our local machine), it is not what we expect to see. We expect to see the address on which the user's browser lives.

We now enable the remote IP valve in server.xml and restart Tomcat. The configuration is as follows.


<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="127\.0\.0\.1" />


Notice how we have to escape the dots in the proxy's IP address. In this configuration file, the IP addresses are regular expressions. Dots would actually match any character, not only the dot.

This is the simplest configuration that corrects the HTTP client's IP address. In this form, the remoteIp filter will only correct the IP address as reported by getRemoteAddr(). It does not for example allow you to determine if the original request was using http or https. If you need to do that, please read remote IP valve's Google Code home page (http://code.google.com/p/xebia-france/wiki/RemoteIpValve) for more and more complex examples.

Now calls to getRemoteAddr() do return the IP addresses we expected to see. The remote IP valve used the x-forwarded-for headers that Apache automatically inserted to give us the expected IP address.

This post is really just to show you how easy it is to start using the remote IP valve. For a much more detailed explanation of this valve and for some enlightening graphics on how the configuration works, please visit this (http://blog.xebia.fr/2009/05/05/tomcat-adresse-ip-de-linternaute-load-balancer-reverse-proxy-et-header-http-x-forwarded-for) and this (http://blog.xebia.fr/2009/11/13/tomcat-ssl-communications-securisees-et-x-forwarded-proto/) blog post by Cyrille (they are in French, translations are here (http://translate.google.com/translate?u=http%3A%2F%2Fblog.xebia.fr%2F2009%2F05 %2F05%2Ftomcat-adresse-ip-de-linternaute-load-balancer-reverse-proxy-et-header-http-x-forwarded-for) and here (http://translate.google.com/translate?u=http%3A%2F%2Fblog.xebia.fr%2F2009%2F11 %2F13%2Ftomcat-ssl-communications-securisees-et-x-forwarded-proto)).

All that remains is for you to remove any hacks around getRemoteIp() that you have in your code. That should be a simple and fun little exercise. :-)

Kees Jan

Cyrille Le Clerc
21-10-2010, 10:26
Thanks again for your interest in the mod_remoteip port in Java.

As an update, this port is also available as a Tomcat filter named RemoteIpFilter (http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#Remote_IP_Filter) since Tomcat 7.0.0 .

Cyrille