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

Reply via email to