Keywords: Servlet Filter | Request Parameter | XSS Mitigation
Abstract: This article explains how to modify request parameters using Servlet filters and HttpServletRequestWrapper without altering the source code, to defend against XSS attacks. It covers core concepts, implementation, and best practices.
Introduction
In an existing web application running on Tomcat 4.1, there is an XSS (Cross-Site Scripting) vulnerability in a page, but the source code cannot be modified. Therefore, writing a Servlet filter to sanitize parameters before they reach the page becomes an effective solution.
Servlet Filters and Request Parameters
Servlet filters are part of the Java EE specification, allowing custom logic to be inserted into the request-processing chain. However, the ServletRequest interface is designed to represent the raw request from the client, so it does not provide a setParameter method to modify parameter values. This ensures the immutability of the request and prevents misleading subsequent processing.
Modifying Parameters with HttpServletRequestWrapper
To modify request parameters without violating the specification, the HttpServletRequestWrapper class can be used. This class allows wrapping an existing request object and overriding the getParameter and getParameterValues methods to return modified values. In the filter's doFilter method, create a wrapped request object and pass it to chain.doFilter.
Here is an example code based on the discussion:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public final class XssFilter implements Filter {
static class FilteredRequest extends HttpServletRequestWrapper {
static String allowedChars = "+-0123456789#*"; // Allowed characters
public FilteredRequest(ServletRequest request) {
super((HttpServletRequest) request);
}
public String sanitize(String input) {
String result = "";
for (int i = 0; i < input.length(); i++) {
if (allowedChars.indexOf(input.charAt(i)) >= 0) {
result += input.charAt(i);
}
}
return result;
}
public String getParameter(String paramName) {
String value = super.getParameter(paramName);
if ("dangerousParamName".equals(paramName)) {
value = sanitize(value);
}
return value;
}
public String[] getParameterValues(String paramName) {
String[] values = super.getParameterValues(paramName);
if (values != null && "dangerousParamName".equals(paramName)) {
for (int i = 0; i < values.length; i++) {
values[i] = sanitize(values[i]);
}
}
return values;
}
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new FilteredRequest(request), response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}
In this example, the FilteredRequest class overrides the getParameter and getParameterValues methods to sanitize specific parameters. The sanitize function only allows certain characters, effectively preventing XSS injection.
Alternative Approaches and Comparison
Another approach is to modify the original Servlet or JSP to use request attributes instead of parameters. The filter can inspect parameters, sanitize them, and set them as attributes using request.setAttribute. This method avoids subclassing but requires changes to other parts of the application, which may not be feasible in all scenarios.
Implementation Details and Best Practices
In practice, sanitization logic should be customized based on specific needs, such as using safer libraries for HTML encoding. Additionally, ensure the filter is correctly configured in web.xml to intercept target URLs. For Tomcat 4.1, pay attention to Servlet API compatibility.
Conclusion
By using HttpServletRequestWrapper to wrap requests, Servlet filters can effectively modify request parameters to defend against XSS attacks without altering the source code. This method adheres to the Servlet specification, ensuring application compatibility and security.