问题
I'm trying to secure my spring boot application using a XSSFilter like this:
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);
}
}
And the wrapper:
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("&","&")
.replace("<", "<")
.replace(">",">")
.replace("\"",""")
.replace("'","'");
}
@Override
public String getParameter(String parameter) {
return replaceXSSCharacters(super.getParameter(parameter));
}
@Override
public String getHeader(String name) {
return replaceXSSCharacters(super.getHeader(name));
}
}
The problem is, that only secures the Request parameters and Headers, not the Request body, and sometimes my Controller receive data using @RequestBody.
So, if i submit to my controller a json like this:
{"name":"<script>alert('hello!')</script>"}
The html chars at the name property doesn't get escaped like i need. How can i escape the RequestBody?
EDIT: This is different from the "duplicated" question. My question is very Specific. How to escape characters on Request Body.
回答1:
I resolved with a custom class:
@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("&");
case '<' : return new SerializedString("<");
case '>' : return new SerializedString(">");
case '\"' : return new SerializedString(""");
case '\'' : return new SerializedString("'");
default : return super.getEscapeSequence(ch);
}
}
}
}
It covers all the cases.
回答2:
- Have a local String field in XSSRequestWrapper which holds the cleaned-up body (probably not suitable for large bodies).
- Populate this field in the constructor by reading request.getInputStream() and cleaning up the body the same way as parameters.
- Override getInputStream and getReader methods of HttpServletRequestWrapper, and construct an InputStream (string -> byte array -> ByteArrayInputStream) and Reader (StringReader) from the String field and return them respectively. Maybe cache the constructed InputStream and Reader objects for better performance for when the methods are called repeatedly.
You may also be interested in cleaning up JSON when it is being deserialized into Java object.
回答3:
To remove XSS characters you just override AbstractJackson2HttpMessageConverter - this converter has responsibility to read request.inputStream to RequestBody object
@Component
public class XSSRequestBodyConverter extends AbstractJackson2HttpMessageConverter {
public XSSRequestBodyConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
Object requestBody = super.read(type, contextClass, inputMessage);
//Remove xss from requestBody here
String requestInStr = objectMapper.writeValueAsString(requestBody);
return objectMapper.readValue(replaceXSSCharacters(requestInStr), Object.class);
}
}
来源:https://stackoverflow.com/questions/49439020/spring-boot-escape-characters-at-request-body-for-xss-protection