我正在尝试使用过滤器检查响应正文中的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中有修改后的主体,但在客户端,主体看起来好像从未修改过。
任何建议都将不胜感激。感谢。
答案 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())