现有的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
不存在 .
在将请求传递给链之前,如何更改请求参数的值?
6 回答
编写一个简单的类,使用getParameter()方法对
HttpServletRequestWrapper
进行子类化,该方法返回输入的已清理版本 . 然后直接将HttpServletRequestWrapper
的实例传递给Filter.doChain()
而不是请求对象 .为了记录,这是我最后写的课程:
正如您所注意到的
HttpServletRequest
没有setParameter方法 . 这是故意的,因为类表示来自客户端的请求,并且修改参数不代表该请求 .一种解决方案是使用
HttpServletRequestWrapper
类,它允许您将一个请求与另一个请求包装起来 . 您可以对其进行子类化,并覆盖getParameter
方法以返回已清理的值 . 然后,您可以将该包装请求传递给chain.doFilter
而不是原始请求 .它是's a bit ugly, but that' s servlet API说你应该做什么 . 如果您尝试将任何其他内容传递给
doFilter
,则某些servlet容器会抱怨您违反了规范,并拒绝处理它 .更优雅的解决方案是更多工作 - 修改处理参数的原始servlet / JSP,以便它需要请求属性而不是参数 . 过滤器检查参数,对其进行清理,并使用已清理的值设置属性(使用
request.setAttribute
) . 没有子类化,没有欺骗,但确实需要您修改应用程序的其他部分 .试试
request.setAttribute("param",value);
. 它对我来说很好 .请找到此代码示例:
您可以使用 Regular Expression 进行清理 . 在调用 chain.doFilter(request, response) 方法之前的内部过滤器中,调用此代码 . 这是示例代码:
我遇到了同样的问题(从Filter中的HTTP请求更改参数) . 我最后使用
ThreadLocal<String>
. 在Filter
我有:在我的请求处理器(
HttpServlet
,JSF控制器或任何其他HTTP请求处理器)中,我得到当前的线程值:好处:
比传递HTTP参数更通用(你可以传递POJO对象)
稍快(无需解析URL以提取变量值)
更优雅的
HttpServletRequestWrapper
样板变量范围不仅仅是HTTP请求(执行
request.setAttribute(String,Object)
时的范围,即您可以访问其他过滤器中的变量) .缺点:
只有当处理过滤器的线程与处理HTTP请求的线程相同时,才能使用此方法(我所知道的所有基于Java的服务器都是这种情况) . 因此,这 will not work when
doing a HTTP redirect (因为浏览器执行了新的HTTP请求,并且无法保证它将由同一个线程处理)
processing data in separate threads ,例如使用
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
时 .您必须能够修改请求处理器/应用程序
一些旁注:
服务器有一个线程池来处理HTTP请求 . 由于这是游泳池:
a来自此线程池的线程将处理许多HTTP请求,但一次只能处理一个(因此您需要在使用后清理变量或为每个HTTP请求定义它)=注意代码如
if (value!=null) { THREAD_VARIABLE.set(value);}
因为您将重用value
为空时前一个HTTP请求的值:保证副作用) .无法保证同一个线程将处理两个请求(可能是这种情况,但您无法保证) . 如果您需要将用户数据从一个请求保留到另一个请求,那么最好使用HttpSession.setAttribute()
JEE @RequestScoped内部使用
ThreadLocal
,但使用ThreadLocal
更通用:您可以在非JEE / CDI容器中使用它(例如在多线程JRE应用程序中)