如何在过滤器中更改http响应的正文

时间:2014-06-27 12:52:30

标签: java httpresponse servlet-filters

我正在尝试使用过滤器检查响应正文中的HTML标记。问题是,如果我改变过滤器中的主体,当它到达客户端时它不会被改变。我尝试了此处显示的解决方案:Looking for an example for inserting content into the response using a servlet filter 但它没有帮助。

我有两个过滤器。 SecureWrapperFilter将请求/响应对象包装在自定义包装器中,XSSFilter使用OWASP编码对html内容进行编码。过滤器如下所示:

public class SecureWrapperFilter implements Filter {

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
        final FilterChain chain) throws IOException, ServletException
    {
        final ServletRequestWrapper securityRequest =
            new ServletRequestWrapper((HttpServletRequest)request);
        final ServletResponseWrapper securityResponse =
            new ServletResponseWrapper((HttpServletResponse)response);
        ESAPI.httpUtilities().setCurrentHTTP(securityRequest, securityResponse);
        chain.doFilter(ESAPI.currentRequest(), ESAPI.currentResponse());
    }

    @Override
    public void destroy() {
    }
}

public class XSSFilter implements Filter {

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
        final FilterChain chain) throws IOException, ServletException
    {      
        final ServletRequestWrapper requestWrapper = (ServletRequestWrapper)request;
        final String body = Encode.forHtmlContent(requestWrapper.getBody());
        requestWrapper.setBody(body);
        chain.doFilter(requestWrapper, response);
        final ServletResponseWrapper responseWrapper = (ServletResponseWrapper)response;
        final byte[] copy = responseWrapper.getCopy();
        final String oldBody = new String(copy, response.getCharacterEncoding());
        final String newBody = Encode.forHtmlContent(oldBody);
        if (!StringUtils.equals(oldBody, newBody)) {
            responseWrapper.getResponse().getOutputStream().write(newBody.getBytes());
        }
    }

    @Override
    public void destroy() {
    }
}

如果我添加一些调试日志,我可以看到securityResponse在SecureWrapperFilter中有修改后的主体,但在客户端,主体看起来好像从未修改过。

任何建议都将不胜感激。感谢。

3 个答案:

答案 0 :(得分:2)

问题在于,在我的XSSFilter中,我将新的响应主体附加到旧的响应主体上。这导致了无效的json,如{"x"="y"}{"escapedx"="escapedy")

我们的客户端反序列化器只打印了第一个json对象,因此我们在客户端看到的只是{"x"=y"}

要解决此问题,我将以下行添加到XSSFilter:

responseWrapper.getResponse().resetBuffer();

responseWrapper.getResponse().getOutputStream().write(newBody.getBytes());

这会清除缓冲区,允许我在下面的行中重写它。客户端的json现在看起来像是:{"escapedx"="escapedy"}

答案 1 :(得分:1)

您需要确保缓冲HttpResponse。如果缓冲区不够大,那么响应将被流式传输到客户端befire您的过滤器被调用。

或许servler在响应上调用flush()?

答案 2 :(得分:0)

发送回json可以用杰克逊完成:

val res = response as HttpServletResponse

res.status = HttpStatus.UNAUTHORIZED.value()
res.contentType = MediaType.APPLICATION_JSON_UTF8_VALUE

res.outputStream.write(ObjectMapper().writeValueAsString(ResponseError(
    "two_factor_auth_failed", "Two Factor Authorization is required to proceed."
)).toByteArray())