使用 servlet 过滤器修改请求参数

2022-08-31 08:44:09

现有的 Web 应用程序正在 Tomcat 4.1 上运行。页面存在 XSS 问题,但我无法修改源代码。我决定编写一个 servlet 过滤器,以便在页面看到参数之前对其进行清理。

我想写一个像这样的过滤器类:

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

在将请求向下传递到链中之前,如何更改请求参数的值?


答案 1

如您所见,没有 setParameter 方法。这是故意的,因为类表示来自客户端的请求,而修改参数不会表示这一点。HttpServletRequest

一种解决方案是使用该类,它允许您将一个请求与另一个请求包装在一起。您可以对其进行子类化,并重写该方法以返回经过清理的值。然后,您可以将该包装的请求传递给该请求,而不是原始请求。HttpServletRequestWrappergetParameterchain.doFilter

这有点丑陋,但这就是servlet API说你应该做的。如果您尝试将其他任何内容传递给 ,某些 servlet 容器会抱怨您违反了规范,并会拒绝处理它。doFilter

一个更优雅的解决方案是更多的工作 - 修改处理参数的原始servlet / JSP,以便它需要请求属性而不是参数。筛选器检查参数,对其进行清理,并使用清理值设置属性(使用 )。没有子类化,没有欺骗,但确实需要您修改应用程序的其他部分。request.setAttribute


答案 2

为了记录在案,这是我最终写的课程:

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) {
    }
}

推荐