-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

All,

On 4/18/2011 9:51 PM, Christopher Schultz wrote:
> I'm leaning more towards just protecting against control characters in a
> header: there's no need to do a complete URL-parse to check for response
> splitting.
> 
> A simple filter that wraps the response and overrides either
> sendRedirect or setHeader(String, String) should do it.
> 
> I'd have to check to see how the two interact... whether calling
> sendRedirect on a wrapped response will also set the header on the
> wrapped response or set the header at a higher level where the wrapper
> won't get called.

Looks like I must override sendRedirect because otherwise the setHeader
call implemented in Response.sendRedirect isn't intercepted by the
wrapper class.

For those interested, see below for the implementation I came up with.

Enjoy,
- -chris

import java.io.IOException;
import java.net.MalformedURLException;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * Prevents the application from setting HTTP headers that include
 * CR or LF characters. Specifically throws a MalformedURLException
 * for the sendRedirect method which is already declared to throw
 * IOException.
 */
public class HttpResponseSplittingPreventionFilter
    implements Filter
{
    public void init(FilterConfig config)
    {
    }

    /**
     * Performs the filtering operation provided by this filter.
     *
     * @param request The request being made to the server.
     * @param response The response object prepared for the client.
     * @param chain The chain of filters providing request services.
     */
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
        throws IOException, ServletException
    {
        if(response instanceof HttpServletResponse)
            response = new Wrapper((HttpServletResponse)response);

        chain.doFilter(request, response);
    }

    /**
     * Called by the servlet container to indicate that a filter is being
     * taken out of service.<p>
     */
    public void destroy()
    {
    }

    class Wrapper
        extends HttpServletResponseWrapper
    {
        Wrapper(HttpServletResponse response)
        {
            super(response);
        }

        public void sendRedirect(String location)
            throws IOException
        {
            if(containsCRorLF(location))
                throw new MalformedURLException("CR or LF detected in
redirect URL: possible http response splitting attack");

            super.sendRedirect(location);
        }

        public void setHeader(String name, String value)
        {
            if(containsCRorLF(value))
                throw new IllegalArgumentException("Header value must
not contain CR or LF characters");

            super.setHeader(name, value);
        }

        public void addHeader(String name, String value)
        {
            if(containsCRorLF(value))
                throw new IllegalArgumentException("Header value must
not contain CR or LF characters");

            super.addHeader(name, value);
        }

        private boolean containsCRorLF(String s)
        {
            if(null == s) return false;

            int length = s.length();

            for(int i=0; i<length; ++i)
            {
                char c = s.charAt(i);

                if('\n' == c
                   || '\r' == c)
                    return true;
            }

            return false;
        }
    }
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk2s66gACgkQ9CaO5/Lv0PDcSgCfbJnJkhqAYeZ/i7TgdGqX9adr
BZ4An1G8gf8EAdV6ywyo0b7c6PWqg+AD
=9kiL
-----END PGP SIGNATURE-----

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

Reply via email to