Search code examples
spring-mvcjacksonhtml-escape-characters

HTML escape with Spring MVC and Jackson Mapper


I am going to escape HTML in Spring MVC with Jackson Mapper to avoid XSS attack. I search for escaping with Jackson alone and how to config Jackson in Spring. I tried to export json with text like "<" ">", I expected it to escape them to &#60; and &#62;. For example, I added some text enclosed with "bold tag" <b>, I expected to see plain bold tag text in the front end html but it ended up so that the text is shown in bold style in the front end html page.

Below is my approach. I don't know why it didn't work out.

public class CustomObjectMapper extends ObjectMapper {  
    public CustomObjectMapper() {
        this.getJsonFactory().setCharacterEscapes(new CustomCharacterEscapes());
    }
}

public class CustomCharacterEscapes extends CharacterEscapes {
    private final int[] asciiEscapes;
    
    public CustomCharacterEscapes() {
        int[] esc = CharacterEscapes.standardAsciiEscapesForJSON();
        esc['<'] = CharacterEscapes.ESCAPE_STANDARD;
        esc['>'] = CharacterEscapes.ESCAPE_STANDARD;
        esc['&'] = CharacterEscapes.ESCAPE_STANDARD;
        esc['\''] = CharacterEscapes.ESCAPE_STANDARD;
        asciiEscapes = esc;
    }
    
    @Override
    public int[] getEscapeCodesForAscii() {
        return asciiEscapes;
    }
    
    @Override
    public SerializableString getEscapeSequence(int ch) {
        return null;
    }
}

Here is the Spring Bean configuration:

<bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <array>
            <bean id="jsonConverter"
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper">
                    <bean class="x.y.z.CustomObjectMapper" />
                </property>
            </bean>
        </array>
    </property>
</bean>

Solution

  • I have never tried to write my own HttpMessageConverter, but I did find this posting that seems pretty relevant to what you want to do. In looking at their solution vs. what you posted here, I can say the biggest differences I noticed was that you did not seem to implement/override the following:

    1. protected boolean supports(Class<?> clazz), which indicates which class type you are supporting (I would recon in your case this would be Object or Serializable if you want it to be generic enough to handle every possibility, or some class specific to your domain objects)
    2. protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage), looks like it's used for the request-side
    3. protected void writeInternal(Object t, HttpOutputMessage outputMessage), which looks like it's used for the response-side

    Another approach might be to simple create a custom Jackson serializer in conjunction with @ResponseBody. Or, better yet, if you have a value that is user-driven, and your storing it in a database, escape the values prior to insertion. That way you don't need to do anything at all, and the value(s) in question would be "safe" from end-to-end. If you wanted to get crazy-fancy, you could write a custom java.beans.PropertyEditor that escapes Strings for HTML and plug that into the mix using the InitBinder.

    Finally, I would like to recommend that, instead of trying to replace the characters on your own, you use something like Apache Commons-Lang's StringEscapeUtils to escape the values.