The X-FORWARDED-FOR HTTP header
Posted 2008-12-02 in Java by Johann.
X-FORWARDED-FOR
is a HTTP header that is inserted by proxies to identify the IP address of the client. It can also be added to requests if application servers are proxied by proxy servers. In this case, the request IP address is always a local address and the client IP address must be extracted from the request.
Since proxies can be chained – for example if the client’s request is already made through a proxy – the X-FORWARDED-FOR
header can contain more than one IP address, separated by commas. In this case, the first one should be used.
Java Code
The following Java code extracts the originating IP address of an HttpServletRequest
object.
public final class HTTPUtils { private static final String HEADER_X_FORWARDED_FOR = "X-FORWARDED-FOR"; public static String remoteAddr(HttpServletRequest request) { String remoteAddr = request.getRemoteAddr(); String x; if ((x = request.getHeader(HEADER_X_FORWARDED_FOR)) != null) { remoteAddr = x; int idx = remoteAddr.indexOf(','); if (idx > -1) { remoteAddr = remoteAddr.substring(0, idx); } } return remoteAddr; } }
JSPs
In a JSP, the X-FORWARDED-FOR
header can be retrieved as follows:
<%= request.getHeader("X-FORWARDED-FOR") %>
Of course, a Servlet Filter could replace the original HttpServletRequest
with a wrapped version that returns the X-FORWARDED-FOR
value.
Example Request
Here is a full request that was made from 129.78.138.66 through the proxy at 129.78.64.103:
2008-12-01 16:00:59,878 INFO AntiScrape - 129.78.138.66, 129.78.64.103: USER-AGENT: … HOST: johannburkard.de PRAGMA: no-cache ACCEPT: */* ACCEPT-ENCODING: identity VIA: 1.1 www-cacheF.usyd.edu.au:8080 (squid/2.6.STABLE5) X-FORWARDED-FOR: 129.78.138.66, 129.78.64.103 CACHE-CONTROL: no-cache, max-age=604800 X-HOST: johannburkard.de X-FORWARDED-PROTO: http
6 comments
It is important to mention that there is no guarantee that the proxy is telling the truth (or that he is telling anything).
Also, the user itself can inject headers, showing his computer as just an other proxy in the chain. For example the user adds:
X-FORWARDED-FOR: 10.100.0.123
And now the proxy would say:
X-FORWARDED-FOR: 129.78.138.66, 129.78.64.103, 10.100.0.123
And make it look like the original host was 10.100.0.123, even thought it was 129.78.64.103.
#2 2009-08-03 by Cyrille Le Clerc
Hello,
As Cd-Man said, the HTTPUtils.remoteAddr() algorithm is subject to x-forwarded-for header spoofing. It can easily be achieved with tools like Firefox add-ons Modify Headers (1) and X-Forwarded-For Spoofer (2).
The forthcoming version of Apache Httpd will offer a secure mechanism to handle X-Forwarded-For with a module called mod_remoteip (3). It relies on the concept of trusted proxies which IP address can be 'swallowed'. The first IP of the list that is not a trusted proxy is seen as the real remote ip. mod_remoteip would not have been tricked by Cd-Man's scenario.
Here are two java ports of mod_remoteip to handle X-Forwarded-For at the Tomcat level with a valve and at the WAR level with a servlet filter : RemoteIpValve (4) and XForwardedFilter (5). In addition to handle X-Forwarded-For, they also integrate X-Forwarded-Proto (ssl).
Thanks to this, request.getRemoteAddr(), request.getRemoteHost(), request.isSecure(), request.getScheme() and request.getServerPort() will expose the values transmitted by X-Forwarded-For and X-Forwarded-Proto rather than the values of the preceding proxy / load balancer.
The RemoteIpValve has been proposed to the Tomcat project as "Bug 47330 - proposal : port of mod_remoteip in Tomcat as RemoteIpValve" (6).
Hope this helps,
Cyrille
(1) https://addons.mozilla.org/en-US/firefox/addon/967
(2) https://addons.mozilla.org/en-US/firefox/addon/5948
(3) http://httpd.apache.org/docs/trunk/mod/mod_remoteip.html
(4) http://code.google.com/p/xebia-france/wiki/RemoteIpValve
(5) http://code.google.com/p/xebia-france/wiki/XForwardedFilter
(6) https://issues.apache.org/bugzilla/show_bug.cgi?id=47330
Cyrille,
I didn't know there was so much involved in this :-)
Thank you for your additions.
#4 2009-08-05 by Cyrille Le Clerc
I didn't know either :-)
The guys who developped mod_remoteip did a impressing work.
I just ported it in Java and added support for x-forwarded-proto to identify incoming SSL request.
Cyrille
#5 2009-11-08 by Cyrille Le Clerc
Hello,
The RemoteIpValve and the XForwardedFilter have been integrated in the Tomcat Project. The RemoteIpValve will be available in the forthcoming Tomcat 6.0.21 version (1) when the XForwardedFilter has been renamed RemoteIpFilter and will be integrated in Tomcat 7 (2).
The Google Code version of XForwardedFilter (3) will still be interesting for people who want to integrate this features in other servlet containers (Glassfish, JBoss, Weblogic, WebSphere, etc) without importing Tomcat jars.
Cyrille.
(1) http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/RemoteIpValve.java?annotate=833535&pathrev=833536
(2) http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/filters/RemoteIpFilter.java?annotate=833155
(3) http://code.google.com/p/xebia-france/wiki/XForwardedFilter
#6 2010-02-02 by Cyrille Le Clerc
Hello Johann,
The RemoteIpValve is now available in Tomcat 6.0.24 standard distribution. No additional download is required for Tomcat.
Cyrille
Subscribe
RSS 2.0, Atom or subscribe by Email.
Top Posts
- DynaCloud - a dynamic JavaScript tag/keyword cloud with jQuery
- 6 fast jQuery Tips: More basic Snippets
- xslt.js version 3.2 released
- xslt.js version 3.0 released XML XSLT now with jQuery plugin
- Forum Scanners - prevent forum abuse
- Automate JavaScript compression with YUI Compressor and /packer/