现有的Web应用程序正在Tomcat 4.1上运行.页面存在XSS问题,但我无法修改源代码.我决定编写一个servlet过滤器来在页面看到之前清理参数.
我想写一个像这样的Filter类:
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) { } }
但ServletRequest.setParameter
不存在.
在将请求传递给链之前,如何更改请求参数的值?
正如您所指出的HttpServletRequest
那样,没有setParameter方法.这是故意的,因为类表示来自客户端的请求,并且修改参数不代表该请求.
一种解决方案是使用HttpServletRequestWrapper
该类,它允许您将一个请求与另一个请求包装起来.您可以对其进行子类化,并覆盖该getParameter
方法以返回已清理的值.然后,您可以将该包装请求传递给chain.doFilter
原始请求.
它有点难看,但这就是servlet API所说的应该做的事情.如果你试图传递任何其他东西doFilter
,一些servlet容器会抱怨你违反了规范,并拒绝处理它.
更优雅的解决方案是更多工作 - 修改处理参数的原始servlet/JSP,以便它需要请求属性而不是参数.过滤器检查参数,对其进行清理,并使用request.setAttribute
已清理的值设置属性(使用).没有子类化,没有欺骗,但确实需要您修改应用程序的其他部分.
为了记录,这是我最后写的课程:
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 { /* These are the characters allowed by the Javascript validation */ static String allowedChars = "+-0123456789#*"; 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 ("dangerousParamName".equals(paramName)) { for (int index = 0; index < values.length; index++) { values[index] = sanitize(values[index]); } } 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) { } }
编写一个简单的类,该类HttpServletRequestWrapper
使用getParameter()方法进行子类化,该方法返回输入的已清理版本.然后通过你的实例HttpServletRequestWrapper
来Filter.doChain()
直接代替请求对象.