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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24452318/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:17:17  来源:igfitidea点击:

How to alter the body of a http response in a filter

javahttpresponseservlet-filters

提问by Ben Green

I am attempting to use a filter to check for HTML tags in a response body. The problem is that if I alter the body in the filter, it isn't altered when it gets to the client. I tried the solution shown here: Looking for an example for inserting content into the response using a servlet filterbut it didn't help.

我正在尝试使用过滤器来检查响应正文中的 HTML 标记。问题是,如果我改变过滤器中的主体,当它到达客户端时不会改变。我尝试了此处显示的解决方案:寻找使用 servlet 过滤器将内容插入响应的示例,但没有帮助。

I have two filters. SecureWrapperFilterwraps the request/response objects in our custom wrapper, and XSSFilteruses OWASP encode to encode for html content. The filters look like this:

我有两个过滤器。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() {
    }
}

and:

和:

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

If I add some debug Logging, I can see that the securityResponsehas the modified body in the SecureWrapperFilter, but on the client side, the body looks as if it was never modified.

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

Any suggestions would be greatly appreciated. Thanks.

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

采纳答案by Ben Green

The problem was that in my XSSFilter, I was appending the new response body onto the old one. This was causing invalid json like {"x"="y"}{"escapedx"="escapedy")

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

Our client deserializer was only printing the first json object so {"x"=y"}was all we were seeing on the client side.

我们的客户端反序列化器只打印第一个 json 对象,所以{"x"=y"}我们在客户端看到的都是这样。

To resolve this problem, I added the following line to the XSSFilter:

为了解决这个问题,我在 XSSFilter 中添加了以下行:

responseWrapper.getResponse().resetBuffer();

before

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

This clears the buffer, allowing me to rewrite it on the line below. My json on the client side now looks like: {"escapedx"="escapedy"}

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

回答by David Roussel

You need to make sure the HttpResponse is buffered. If the buffer is not big enough, then the reponse will be streamed to the client befire your filter is called.

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

Or maybe the servler is calling flush() on the response?

或者也许服务器正在对响应调用flush()?

回答by shredding

Sending back json can be done with Hymanson:

可以使用 Hymanson 发送回 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())