An existing web application is running on Tomcat 4.1. There is an XSS issue with a page, but I can't modify the source. I've decided to write a servlet filter to sanitize the parameter before it is seen by the page.
I would like to write a Filter class like this:
import java.io.*;
import javax.servlet.*;
public final class XssFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
String badValue = request.getParameter("dangerousParamName");
String goodValue = sanitize(badValue);
request.setParameter("dangerousParamName", goodValue);
chain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}
But ServletRequest.setParameter
doesn't exist.
How can I change the value of the request parameter before passing the request down the chain?
You can use Regular Expression for Sanitization. Inside filter before calling chain.doFilter(request, response) method, call this code. Here is Sample Code:
I had the same problem (changing a parameter from the HTTP request in the Filter). I ended up by using a
ThreadLocal<String>
. In theFilter
I have:In my request processor (
HttpServlet
, JSF controller or any other HTTP request processor), I get the current thread value back:Advantages:
HttpServletRequestWrapper
boilerplaterequest.setAttribute(String,Object)
, i.e. you can access the variable in other filtrers.Disadvantages:
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
.Some side notes:
The server has a Thread pool to process the HTTP requests. Since this is pool:
if (value!=null) { THREAD_VARIABLE.set(value);}
because you will reuse the value from the previous HTTP request whenvalue
is null : side effects are guaranteed).HttpSession.setAttribute()
@RequestScoped
internally uses aThreadLocal
, but using theThreadLocal
is more versatile: you can use it in non JEE/CDI containers (e.g. in multithreaded JRE applications)Try
request.setAttribute("param",value);
. It worked fine for me.Please find this code sample:
Write a simple class that subcalsses
HttpServletRequestWrapper
with a getParameter() method that returns the sanitized version of the input. Then pass an instance of yourHttpServletRequestWrapper
toFilter.doChain()
instead of the request object directly.As you've noted
HttpServletRequest
does not have a setParameter method. This is deliberate, since the class represents the request as it came from the client, and modifying the parameter would not represent that.One solution is to use the
HttpServletRequestWrapper
class, which allows you to wrap one request with another. You can subclass that, and override thegetParameter
method to return your sanitized value. You can then pass that wrapped request tochain.doFilter
instead of the original request.It's a bit ugly, but that's what the servlet API says you should do. If you try to pass anything else to
doFilter
, some servlet containers will complain that you have violated the spec, and will refuse to handle it.A more elegant solution is more work - modify the original servlet/JSP that processes the parameter, so that it expects a request attribute instead of a parameter. The filter examines the parameter, sanitizes it, and sets the attribute (using
request.setAttribute
) with the sanitized value. No subclassing, no spoofing, but does require you to modify other parts of your application.For the record, here is the class I ended up writing: