@InitBinder with @RequestBody accelerating XSS in Spring 3.2.4

I have an annotated @RequestBody argument in my method similar to this:

 @RequestMapping(value = "/courses/{courseId}/{name}/comment", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) public @ResponseBody CommentContainer addComment(@PathVariable Long courseId, @ActiveAccount Account currentUser, @Valid @RequestBody AddCommentForm form, BindingResult formBinding, HttpServletRequest request) throws RequestValidationException { ..... } 

Then I have the annotated @InitBinder method in the same controller:

 @InitBinder public void initBinder(WebDataBinder dataBinder) { dataBinder.registerCustomEditor(AddCommentForm.class, new StringEscapeEditor()); } 

My StringEscapeEditor not working. But my initBinder method is there. Therefore, it does not display my form in the output editor. This seems correct after reading this thread (where it looks like @RequestMapping not supported by @InitBinder ):

spring mvc @InitBinder not called when processing ajax request

And I tested the @PathVariable line @PathVariable , and then my editor works.

This is a big deal in my application, since most of my bindings are done using @RequestBody , and it would be great if I could apply some custom bindings to it.

What is the most common way to solve this problem? and avoid my input for script attacks.

+3
source share
1 answer

To avoid XSS, I suggest that escaping be done when outputting data, since proper escaping depends on the output.

If the JSON response generated by @ResponseBody is consumed directly by the client and there is no way for XSS to escape the content, then JacksonMessageConverter can be configured to perform XSS escaping in strings.

You can configure JacksonMessageConverter as follows:

1) First we create an ObjectMapper factory that will create our custom mapper object:

 public class HtmlEscapingObjectMapperFactory implements FactoryBean<ObjectMapper> { private final ObjectMapper objectMapper; public HtmlEscapingObjectMapperFactory() { objectMapper = new ObjectMapper(); objectMapper.getJsonFactory().setCharacterEscapes(new HTMLCharacterEscapes()); } @Override public ObjectMapper getObject() throws Exception { return objectMapper; } @Override public Class<?> getObjectType() { return ObjectMapper.class; } @Override public boolean isSingleton() { return true; } public static class HTMLCharacterEscapes extends CharacterEscapes { private final int[] asciiEscapes; public HTMLCharacterEscapes() { // start with set of characters known to require escaping (double-quote, backslash etc) 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; } @Override public int[] getEscapeCodesForAscii() { return asciiEscapes; } // and this for others; we don't need anything special here @Override public SerializableString getEscapeSequence(int ch) { return new SerializedString(StringEscapeUtils.escapeHtml4(Character.toString((char) ch))); } } } 

(inspiration for HtmlCharacterEscapes came from this question: HTML output using Spring MVC and Jackson Mapper )

2) Then we register a message converter that uses our custom object mapping (example in xml config):

 <bean id="htmlEscapingObjectMapper" class="com.example.HtmlEscapingObjectMapperFactory" /> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" p:objectMapper-ref="htmlEscapingObjectMapper" /> </mvc:message-converters> </mvc:annotation-driven> 

Now all JSON messages created by @ResponseBody should have strings escaped as specified in HTMLCharacterEscapes.

Alternative solutions to the problem:

  • XSS removes what you need in the body of the controller after the objects have been deserialized
  • possibly XSS javascript escape on client before outputting content

In addition to performing output escaping, it may also be useful to do some input validation (using standard Spring validation methods) to block some of the content that you do not want to enter into the system / database.

EDIT: JavaConfig

I have not tried this, but in Java configuration it should work as follows (you will not need a factory Bean from above, because in this case you can configure everything in the configuration):

 @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); converters.add(buildHtmlEscapingJsonConverter()); } private MappingJacksonHttpMessageConverter buildHtmlEscapingJsonConverter() { MappingJacksonHttpMessageConverter htmlEscapingConverter = new MappingJacksonHttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.getJsonFactory().setCharacterEscapes(new HTMLCharacterEscapes()); htmlEscapingConverter.setObjectMapper(objectMapper); return htmlEscapingConverter; } 

Keep in mind that any other default non-json message converters that will normally be configured will now be lost (for example, XML converters, etc.), and if you need them, you will need to add them manually (you you can see that active is the default here in section 2.2: http://www.baeldung.com/spring-httpmessageconverter-rest )

+7
source

Source: https://habr.com/ru/post/1264495/


All Articles