请求正文中的Spring Boot转义字符用于XSS保护

时间:2018-03-22 21:48:58

标签: spring spring-mvc spring-boot xss

我正在尝试使用像这样的XSSFilter保护我的spring启动应用程序:

public class XSSFilter implements Filter {

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

    @Override
    public void destroy() { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
    }

}

包装器:

public class XSSRequestWrapper extends HttpServletRequestWrapper {

    public XSSRequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
    }

    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);

        if (values == null) {
            return null;
        }

        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = replaceXSSCharacters((values[i]));
        }

        return encodedValues;
    }

    private String replaceXSSCharacters(String value) {
        if (value == null) {
            return null;
        }

        return value
                .replace("&","&#38;")
                .replace("<", "&#60;")
                .replace(">","&#62;")
                .replace("\"","&#34;")
                .replace("'","&#39;");
    }

    @Override
    public String getParameter(String parameter) {
        return replaceXSSCharacters(super.getParameter(parameter));
    }

    @Override
    public String getHeader(String name) {
        return replaceXSSCharacters(super.getHeader(name));
    }

}

问题是,只保护Request参数和Headers,而不是Request body,有时我的Controller使用@RequestBody接收数据。

所以,如果我向我的控制器提交一个像这样的json:

{"name":"<script>alert('hello!')</script>"}

name属性的html字符不会像我需要的那样被转义。我如何逃避RequestBody?

编辑: 这与“重复”问题不同。我的问题很具体。如何在Request Body上转义字符。

3 个答案:

答案 0 :(得分:0)

  1. 在XSSRequestWrapper中有一个本地String字段,用于保存已清理的主体(可能不适合大型主体)。
  2. 通过读取request.getInputStream()并以与参数相同的方式清理正文,在构造函数中填充此字段。
  3. 覆盖HttpServletRequestWrapper的getInputStream和getReader方法,并从String字段构造一个InputStream(string - &gt; byte array - &gt; ByteArrayInputStream)和Reader(StringReader)并分别返回它们。也许缓存构造的InputStream和Reader对象,以便在重复调用方法时获得更好的性能。
  4. 当JSON being deserialized进入Java对象时,您可能还有兴趣清理它。

答案 1 :(得分:0)

要删除XSS字符,您只需重写AbstractJackson2HttpMessageConverter-此转换器负责将request.inputStream读取到RequestBody对象

Grouper

答案 2 :(得分:0)

我解决了一个自定义类:

@Configuration
public class AntiXSSConfig  {

    @Autowired()
    public void configeJackson(ObjectMapper mapper) {
        mapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static class HTMLCharacterEscapes extends JsonpCharacterEscapes {

        @Override
        public int[] getEscapeCodesForAscii() {
            int[] asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
            // and force escaping of a few others:
            asciiEscapes['<'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['>'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['&'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['"'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['\''] = CharacterEscapes.ESCAPE_CUSTOM;
            return asciiEscapes;
        }

        @Override
        public SerializableString getEscapeSequence(int ch) {
            switch (ch) {
                case '&' : return new SerializedString("&#38;");
                case '<' : return new SerializedString("&#60;");
                case '>' : return new SerializedString("&#62;");
                case '\"' : return new SerializedString("&#34;");
                case '\'' : return new SerializedString("&#39;");
                default : return super.getEscapeSequence(ch);
            }
        }
    }
}

它涵盖了所有情况。