Cross-site Scripting, programming, Security, Spring, Web Development

Prevent cross-site scripting when using JSON objects using ESAPI and Jackson framework 1.7.x


Recently I have had the oppertunity to fix a cross-site-scripting problem. The problem is: a lot of JSON objects are being sent over the wire and the data is not being html escaped. This means that anyone who would put html data IN would get it out and make any user vulnerable for XSS attacks.

In this case, JSON objects are being created by using the MappingJacksonHttpMessageConverter. This is deliverd by the Spring framework. Normally it is instantiated when you use spring-mvc (using the mvc-annotation tag). This allowed us to just return an object and the MappingJacksonHttpMessageConverter would take care of translating it into a JSON object.

In order to influence the creation of the JSON object and make it encode HTML for String values we need to do a few things:

  1. Create a Custom Object Mapper and wire into Spring
  2. Create a JsonSerializer that encodes HTML (using ESAPI)
  3. Register the JsonSerializer in the CustomObjectMapper

Create a Custom Object Mapper and wire into Spring

However, now we want to change the value serialized by the MappingJacksonHttpMessageConverter. So how do we do that? The MappingJacksonHttpMessageConverter uses an ObjectMapper. So in order to get the ObjectMapper map the values to an encoded one we need to create a custom Object mapper.

public class CustomObjectMapper extends org.codehaus.jackson.map.ObjectMapper {

At first we leave it empty. We want to make Spring make use of our CustomObjectMapper first. In order to do that you need to write out the mvc-annotation tag, because we need to inject our CustomObjectMapper in the the MappingJacksonHttpMessageConverter. This is a bit difficult to figure out at first, but for your convinience I have proveded the configuration you need.

<bean id="CustomObjectMapper" class="your custom object mapper"/>

<bean id="MappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
	<property name="objectMapper" ref="CustomObjectMapper"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
	<property name="order" value="1" />
	<property name="customArgumentResolver" ref="sessionParamResolver"/>
	<property name="webBindingInitializer">
	<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
		<!-- <property name="conversionService" ref="conversionService" />  -->
		<property name="validator" ref="validator" />
	</bean>
	</property>
	<property name="messageConverters">
		<list>
			<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
			<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
			<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
			<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
			<ref bean="MappingJacksonHttpMessageConverter"/>
		</list>
	</property>
</bean>

As you can see, the AnnotationMethodHandlerAdapter is the bean where everything is getting wired into. The messageConverters property contains a list of converters. The last entry is where the MappingJacksonHttpMessageConverter is referenced. Normally it is defined like the beans above it. But since we want to inject our own CustomObjectMapper it is done this way.

Create a JsonSerializer that encodes HTML (using ESAPI)

Now we know our CustomObjectMapper is used, we can start the part where we want to influence the way the jackson framework serializes our objects to JSON. In order to do that we create our own JsonSerializer. Then, we override the serialize method and make sure the provided jsonGenerator is writing our encoded value.

Code:

public class JsonHtmlXssSerializer extends JsonSerializer {

   public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
      if (value != null) {
         String encodedValue = encodeHtml(value);
         jsonGenerator.writeString(encodedValue);
      }
   }

}

So this class extends from org.codehaus.jackson.map.JsonSerializer, and implements its own serialize method. The method encodeHtml will use the ESAPI encoding functions to escape HTML.

 

Implementing this is very easy:

   protected String encodeHtml(String html) {
      DefaultEncoder encoder = new DefaultEncoder();
      return encoder.encodeForHTML(html);
   }

The defaultEncoder is from ESAPI allowing us to encode the HTML.

 

Register the JsonSerializer in the CustomObjectMapper

The final step is to register the JsonSerializer within the ObjectMapper used by Spring. Doing that using Jackson 1.7.0 is very easy. Using the provided SimpleModule class we can easily add our own Serializer to the ObjectMapper. We do that by creating our own default constructor, which will register our serializer. Like so:

@Component
public class CustomObjectMapper extends org.codehaus.jackson.map.ObjectMapper {

   public CustomObjectMapper() {
      SimpleModule module = new SimpleModule("HTML XSS Serializer", new Version(1, 0, 0, "FINAL"));
      module.addSerializer(new JsonHtmlXssSerializer());
      this.registerModule(module);
   }
}
About these ads
Standard

6 thoughts on “Prevent cross-site scripting when using JSON objects using ESAPI and Jackson framework 1.7.x

  1. Pingback: Tweets that mention Prevent cross-site scripting when using JSON objects using ESAPI and Jackson framework 1.7.x « Stefan Hendriks' Blog -- Topsy.com

  2. Julian Hjortshoj says:

    Thanks for this very helpful post. I did find one bit of missing configuration that you will need when removing the tag however.

    Without this markup or something like it, service methods don’t get mapped, and nothing functions:

  3. Julian Hjortshoj says:

    looks like the markup got eaten from my last comment. Let me try again with html encoding…

    Thanks for this very helpful post. I did find one bit of missing configuration that you will need when removing the mvc:annotation-driven tag however.

    Without this markup or something like it, service methods don’t get mapped, and nothing functions:
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="order" value="0" />
    </bean>

  4. Joe says:

    Hi,
    Great post!
    Why did you choose to escape the strings on the way out and not on the way in?
    Am in a similar junction and I’m deliberating this exact choice
    It seems to me that I’d rather have everything sanitized before it gets in, no?

    • stefanhendriks says:

      Basically I believe you either check for input, or you do something on the output side. In this case, we wanted to store data as is. The disadvantage for checking on the input is that if you have a bug in your translation/security code the way in, you have potential malformed data. When you do the xss security check on the output side you can easily fix that, and no data is potentially corrupted.

      Also checking the way in, is very hard to guarentee. While showing data in an html view is pretty easy.

      • Joe says:

        Thanks! I decided to go on the output for different reasons (mainly that html-encoding is a defence which should be reserved for when outputting to html. I may have other views (cli) which don’t require this). Your reasons just strengthen my decision. Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s