Java/Spring web applications security: XSS

I recently worked on a Java and Spring based web application for a client in retail banking. Obviously, security was a prime concern and we had to take special care to plug any holes. In this series, I will present some of the most important security concerns that every internet facing application must (ideally) handle. I will also give the solutions for a Java + Spring MVC based web application.

In this part, I discuss CSS (Cross-site scripting or script injection) attacks and the way around them.

Cross-site Scripting

Cross-site scripting (CSS or XSS) is a type of vulnerability that allows attackers to inject malicious client-side scripts into web sites e.g. Javascript. These malicious scripts are injected through the inputs on the forms on the site. For example, a site could have a text input to allow the user to enter a product to search for. An attacker can enter a malicious script into the form field. If the search fails, which it should as there would be no such product, an error message might be displayed containing the entered search string, telling the user that no such product was found. Bang! The attacker rejoices. The malicious script got executed when the browser tried to display the search string as part of the error message as the script will simply become embedded in the output HTML.

The Solution: HTML escaping

The basic principle to follow in order to tackle these kind of attacks is to apply full HTML escaping on the form input. Convert all special characters into their corresponding HTML entity references (e.g. < into &lt;) as defined in HTML 4.01 recommendation. The script injection attacks work because the script becomes embedded in the HTML and gets executed by the browser when the HTML is rendered. After escaping, the script is no longer a valid script and gets embedded as just pure text.

There are two approaches to the implementation of the above principle depending on exactly when the HTML escaping is applied.

Approach#1: Escaping of Input

In the first approach, the escaping is applied at input-time when the form field values are bound to the form backing beans in the application. Since the HTML escaping gets applied to incoming data, the application sees and stores the values in the escaped form. When these values are displayed back on the web-site pages, the risk of a malicious script executing is no more there as the script is no more a valid script. The text gets rendered just as it was entered.

When building a Spring MVC application using Spring’s SimpleFormController, an easy way to do this is to hook into the form binding process. First, define a class that extends from java.beans.PropertyEditorSupport and takes care of converting form input strings to the corresponding backing bean field values and vice versa. You’ll need to override two methods – setAsText and getAsText as follows.

import java.beans.PropertyEditorSupport;
import org.springframework.web.util.HtmlUtils;

public class HtmlEscapeStringEditor extends PropertyEditorSupport {
	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		String out = "";
		if(text != null)
			out = HtmlUtils.htmlEscape(text.trim());

		setValue(out);
	}

	@Override
	public String getAsText() {
		String out = (String) getValue();
		if(out == null)
			out = "";
		return out;
	}
}

It’s pretty straightforward. I used the html escaping method provided by the Spring framework’s HtmlUtils class that supports full HTML escaping. This is also a very good place to place the trimming logic so that all your input values are trimmed before being bound to form backing object automatically.

Next, to hook this property editor into the binding process, override the initBinder method in your form controller (the class that extends SimpleFormController) and register this editor.

@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
	binder.registerCustomEditor(String.class, new HtmlEscapeStringEditor());
}

This can be conveniently placed in the base form controller class of your application, if there is one, from which all other form controllers extend. That’s all there is to it.

Approach#2: Escaping of output

With the previous approach, the values get stored in the application model and the persistence in their escaped form. Sometimes, this may not be the desired behavior. In such cases, we can take a second approach where we don’t process the input at all and store the values on as-is basis. The HTML escaping is applied when rendering the value back on a page.

Spring framework directly supports this at three different levels:

  • Application level

HTML escaping for all Spring tags can be turned on at the application level by specifying a context parameter named defaultHtmlEscape in the web.xml and setting it to true:

<context-param>
	<param-name>defaultHtmlEscape</param-name>
	<param-value>true</param-value>
</context-param>

If the value is specified as false, no escaping will be applied to any of the tags. Note that the default behavior, when no defaultHtmlEscape context parameter is defined, is to apply HTML escaping to all Spring tags in the form tag library (that render values), but not to the other tags that merely expose values but don’t render the values themselves.

  • Page level

Spring can be asked to turn on/off HTML escaping for all form tags on a specific page by using a Spring tag declaration at the top of the page:

<spring:htmlEscape defaultHtmlEscape="true" />

Only the form tags declared after the above tag declaration will use HTML escaping. If we want it to apply to all the tags on the page, it should be declared before all of them.

  • Tag level

Spring can be asked to turn HTML escaping on/off for a specific form tag by setting the htmlEscape attribute of the form tag to true:

<form:input path="name" htmlEscape="true" />

Which approach to take?

Which approach you should take depends on the kind of application you are developing. Can your application afford to store form inputs as they were entered or do you think that even that might be risky. It could be risky due to the ways that data is used elsewhere in the application. Thus, escaping at input-time provides soewhat better security. On the other hand, in some cases, it may be desirable that values be stored as-is due to some dependency and you will use escaping at output-time. Note that even if you decide to do escaping at input-time, you can always de-escape the data before it is used elsewhere in the application, if need be. However, it must never be de-escaped on the way to the JSPs. That’s the whole idea basically.

Now a *caveat*: In most applications, JSP pages are built by mixing Spring’s form tags with the standard JSTL tags as well as JSP 2.0’s embedded ${...} expressions. While the JSTL’a <c:out> tag performs XML escaping (which is sufficient for most modern browsers), the embedded ${...} expressions do not perform any kind of escaping! So apart from using the above described mechanisms to perform HTML escaping for Spring’s form tags, any embedded use of ${...} must to be replaced with <c:out value="${...}"/> in order to guard against CSS attacks!

Advertisements

One Response to Java/Spring web applications security: XSS

  1. Faraz Rafi says:

    Thanks a lot Samit. Your solution really solved the issue I had been having for weeks. Very nicely written article.

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

%d bloggers like this: