-----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: [email protected]
For additional commands, e-mail: [email protected]