Makes sense. I did not dig through the code of the "full version" RemoteIpValve 
so much, just enough to get the general idea (or maybe just enough to get into 
trouble).

I have to look at the docs of our load balancer or maybe just add the proto 
header to the log files to see what values it gets. I know that with squid we 
are fine, and the server is generally accessible only through the load balancer 
or reverse proxy.

If I can make a suggestion for the docs on google code, be specific that this 
valve should be in the engine and precede all other elements of the engine. 
This makes everything work smoothly. It may also be possible to put it outside 
the engine, not sure if that is a general "safe" case.

I think the only real solution here is as you implemented, a valve that 
precedes log valves and other valves (many of which use the IP). Keeps the rest 
of the code clean and simple, the configuration is in one place instead of "all 
over the place".

By the way is it "proxied" or "proxyfied" request? :)

E

----- Original Message -----
From: Cyrille Le Clerc <clecl...@xebia.fr>
To: Tomcat Users List <users@tomcat.apache.org>
Sent: Wed, 21 Oct 2009 06:31:57 -0700 (PDT)
Subject: Re: Cannot set remote address in valve (Tomcat 5.5)

   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




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to