Hello Elli, From what I understand of your architecture, I would configure RemoteIpValve with :
<Valve className = "org.apache.catalina.connector.RemoteIpValve" internalProxies = "@load-balancer-ip" trustedProxies = "@the-trusted-proxy-that-is-not-the-load-balancer" protocolHeader = "x-forwarded-proto" /> Note : - do not forget to "regexp escape' the ip adresses in internalProxies and trustedProxies attributes. - do not declare protocolHeader="x-forwarded-proto" if your load balancer do not manage it - more docs at http://code.google.com/p/xebia-france/wiki/RemoteIpValve Thanks to this, - the 99% direct requests will reach Tomcat with x-forwarded-for="@clientIp" - 1% proxyfied requests will reach Tomcat with x-forwarded-for="@clientIp, @the-trusted-proxy-that-is-not-the-load-balancer" Does it make sense ? Cyrille -- Cyrille Le Clerc clecl...@xebia.fr cyri...@cyrilleleclerc.com http://blog.xebia.fr On Wed, Oct 21, 2009 at 6:57 AM, Elli Albek <e...@sustainlane.com> wrote: > > A question: How do you know that a proxy is trusted? Is it by providing a > list of trusted IPs in the configuration of the filter? > > Our load balancer is always adding the client IP as the first in the list, > and it does not add its own IP to the list. The header > has one IP +99% of the times, the other times there is an additional IP of a > proxy that is not our load balancer (reverse proxy). > > So in that case, we can check that the request comes from a trusted IP list > (known load balancers), and only then try to change the > IP. If the client IP does not come from the load balancer, it is basically a > pass through. > > For our system the first IP is what the load balancer sees, and the only way > to spoof it is to access the server not through the > load balancer. If you send a request with a spoofed header to the laod > balancer, it will still add the IP of the spoofer in the > beginning of the list. > > This may not be the general case for proxies, it is only for this case. > > E > > -----Original Message----- > From: Cyrille Le Clerc [mailto:clecl...@xebia.fr] > Sent: Thursday, October 08, 2009 1:04 AM > To: Tomcat Users List > Subject: Re: Cannot set remote address in valve (Tomcat 5.5) > > Hello Elli, > > I am afraid there may be a flaw in the algorythm looking for the > first IP of the coma delimited x-forwarded-for header without > ensuring that this first IP has been set by a trusted proxy and not by > the requester ( getFirstIP(xforwardedForHeaderValue) ). Such spoofing > 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 such x-forwarded-for header spoofing. > > 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). > These java ports integrate the same trusted proxies concept to prevent > spoofing. > > Cyrille > -- > Cyrille Le Clerc > clecl...@xebia.fr cyri...@cyrilleleclerc.com > http://blog.xebia.fr > > > (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 > > > On Mon, Oct 5, 2009 at 11:19 PM, Elli Albek <e...@sustainlane.com> wrote: > > > > Hi, > > > > We can add the header to the custom valves, but then in addition we have to > > change a few log file configurations, create a servlet filter and maybe > > something else I cant think of now. Basically doing the same thing a few > > times and keeping track of all the places that depend on the header. Ideally > > this would all be corrected once in the beginning of the request processing > > pipeline, so log file configuration, other valves and the war files will > > remain unchanged. > > > > > > > > Attached a Valve that does that. This is the minimum code necessary, so it > > should not have any significant performance impact. > > > > Feel free to use as is, not guaranteed to work, no expressed on implied > > warranties, not FDIC insured and may loose value. > > > > > > > > To configure Tomcat add to server.xml: > > > > > > > > <Service name="Catalina"> > > > > <Connector port="8080" .../> > > > > <Engine defaultHost="localhost" name="Catalina"> > > > > <!-- This should precede all other configuration in the engine > > --> > > > > <Valve className="org.apache.catalina.connector.RemoteIPValve"/> > > > > > > > > Java class/jar should be placed in /server/lib or /server/classes > > > > > > > > E > > > > > > > > > > > > > > > > package org.apache.catalina.connector; > > > > > > > > import java.io.IOException; > > > > import java.util.regex.Matcher; > > > > import java.util.regex.Pattern; > > > > > > > > import javax.servlet.ServletException; > > > > > > > > import org.apache.catalina.connector.Request; > > > > import org.apache.catalina.connector.Response; > > > > import org.apache.catalina.valves.ValveBase; > > > > > > > > /** > > > > * A valve that extracts the remote IP of the client from an HTTP header > > field > > > > * passed by the proxy, and set it in the request as the original client IP. > > > > * This valve should be the first valve in the engine, so log valves (and > > > > * others) will see the real client IP without requiring the same code > > again. > > > > * > > > > * @author Elli Albek, www.sustainlane.com > > > > */ > > > > public class RemoteIPValve extends ValveBase { > > > > > > > > private static final Pattern ipExpr = > > Pattern.compile("^[\\da-fA-F]+(\\.[\\da-fA-F]+)+"); > > > > > > > > private String forwardedForHeader = "X-Forwarded-For"; > > > > > > > > public void invoke(Request request, Response response) throws > > IOException, ServletException { > > > > > > > > String header = request.getHeader(forwardedForHeader); > > > > String forwardedIP = getFirstIP(header); > > > > if (forwardedIP != null) > > > > request.remoteAddr = forwardedIP; > > > > > > > > next.invoke(request, response); > > > > } > > > > > > > > /** > > > > * Return the first IP address in a string that may contain an IP list > > > > */ > > > > static final String getFirstIP(String header) { > > > > if (header == null) > > > > return null; > > > > Matcher m = ipExpr.matcher(header); > > > > if (m.find()) { > > > > return m.group(); > > > > } > > > > return null; > > > > } > > > > > > > > public void setForwardedForHeader(String forwardedForHeader) { > > > > this.forwardedForHeader = forwardedForHeader; > > > > } > > > > > > > > public String getInfo() { > > > > return "RemoteIPValve"; > > > > } > > > > } > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org