Retrofit your webapp with generic XSS protection
Door: Jan-Kees van Andel, 25 June 2009On my current project (online e-banking application for a medium/large scale bank), we needed to add Cross Site Scripting (XSS) protection afterwards. Well, actually, we had a working XSS protection mechanism in place, but the security auditors pointed out the implementation had flaws. But we’ll get to that later.
Cross Site Scripting?
First, let me explain what Cross Site Scripting (XSS) is. XSS is a hack where malicious code (JavaScript/HTML) is injected into a trusted site. With trusted, I mean the user trusts the site, which is usually the case with e-banking websites. At least, I hope so.
A simple example is a web site which contains a search box, like the following.
<form action="/search.do" method="GET"> <input type="text" name="searchString" value="Enter something here" /> <input type="submit" value="Search" /> </form>
When the user submits the form, a request is made to the following URL: /search.do?searchString=[THE_USER_INPUT]
The application responds with a page, containing the results, including a summary of the search criteria, and also the search form, prefilled with the search string the user entered, like here.
<!-- Some HTML -->
<form action="search.jsp" method="GET">
<input type="text" name="searchString" value="${param.searchString}" />
<input type="submit" value="Search" />
</form>
<table id="results">
<!-- The search results -->
</table>
<!-- The rest of the site -->So far, so good, right?
No, wrong!!!
Suppose a hacker enters the following value into the searchString box:
"/><script>alert("hello")</script><p id="
You’ll see an alert box with the message: “Hello”. You have injected a script into your web page.
But why would anyone hack his own browser session? That’s not the danger here. The danger is that a hacker can create an URL, like
http://www.yoursite.com/search.do?searchString="/><script>alert("hello")</script><p id="
and send it to other people.
When they click on it, the script gets executed in their browser.
Of course, an alert window is harmless, but what if I inject some DOM scripting to create a form where the user must enter his or her credentials for the attacked site? Or an image to automatically trigger a “Button click” (this is actually a case of Cross Site Request Forgery)? With such a leak, I can do almost anything on your page, without you knowing.
Let’s see what happens when the login page of your bank is vulnerable to XSS. Phishing becomes easy as stepping on kittens!
As you’re probably now aware of, XSS is a great “enabler” for all kind of other hacks. And the fun part is, hackers can spot XSS flaws easily and often using automatic tools. Not scared yet? In that case, I hope you’re not working on the website where I perform my electronic payments!
You should be scared for these kind of leaks.
Countermeasures
In theory, it is very easy to protect your website against XSS. Just escape all variables, according to the escaping rules that apply for the markup/script language you are about to put the variables in. Apache Commons Lang has a utility for this purpose: the class StringEscapeUtils with its method escapeHtml and some others. escapeHtml is probably the method you’ll need most, since most variables are outputted in HTML tags.
Why is this fix enough? Well, just test it out with the example above. We modify the JSP to escape the input before rendering it to the client, as shown below.
<%
String param = request.getParameter("searchString");
if (param == null) param = "";
String escaped = org.apache.commons.lang.StringEscapeUtils.escapeHtml(param);
%>
<form action="search.jsp" method="GET">
<input type="text" name="searchString" value="<%=escaped%>"/>
<input type="submit" value="Search"/>
</form>The difference is that I added an escaping routine here. Nothing fancy, except that the “obvious” happens. The user input is shown on the screen in exactly the same way the user has entered it.
You see, no validation or black-/whitelists are needed, which is great, since you don’t want to bother users with security.
Some caveats, which become quite annoying later on.
- Timing is essential with regards to escaping. You cannot do it on your input parameters, since you’ll then end up with HTML encoded texts in your backend systems (that was the flaw I was talking about in the introduction). You also don’t want to be bothered with HTML encoding in your Java business logic, so input filtering is not the way to go. You definitely need to filter on the output, just before you render your page back to the client.
- You may not escape a variable twice, since the user ends up with HTML codes in his/her UI. When escaping > twice, it first becomes > and after the second pass, it becomes >, which is not only wrong with regards to usability, it also opens up some interesting new security holes.
- When you persist user input unencoded, which you should, you also need to escape all variables that come from there before rendering the web page. Essentially, you just need to escape every variable that is inserted into the web page, since it may (directly or indirectly) be manipulated by a malicious user.
Implementation
So, we need a way to escape all user input just before it is rendered. What are the options?
-
Custom JSP function
Probably the easiest way to escape special characters is by implementing a JSP custom function, like the JSF “outputText” component:
<h:outputText escape="true" value="<script>" />
. This one is easy to implement. It’s just a burden to edit all 200 JSP files (and the same amount of JSP Tag files) in our project and add the function at all places where a variable is used. The second issue is that you also need to be sure you don’t escape a variable twice, since that results in strange output and, ironically, new security holes. This is especially the case with tag attributes. Do you escape in the tag or in the calling code? You’ll need a strategy there. Finally, and probably most importantly, this solution will probably become a maintenance nightmare. JSPs are cluttered with these custom functions and future maintainers may never forget one when making changes. Something more generic would be nice.
-
ELResolver?
ELResolvers are added to JSP with version 2.1. We use Tomcat 6, so that’s great. However, the ELResolver mechanism differs greatly from, for example, the JSF VariableResolver mechanism. VariableResolvers are implemented using decoration, which makes them very useful to intercept all variable access and modify the responses. ELResolvers are implemented as a CoR and the implementation makes it impossible to create a custom filtering mechanism for all variables. It is also not the right place for this kind of logic. Why? Imagine a JSP Tag file. In the calling JSP file, you use EL to pass an argument to the tag and in the JSP Tag file, you use EL to put the argument in the HTML. With an ELResolver solution, variables get escaped twice. Not good. -
Tomcat hooks, AOP, Javassist?
There are other ways to hook into the JSP/Servlet lifecycle. Containers provide vendor specific hooks to hook into the lifecycle, but unfortunately, no Tomcat hooks to help us here. But we’re not defeated yet! We can use AOP or a bytecode library to enhance some core Tomcat classes. Of course, we’re entering the black magic room here, but if it works… Unfortunately, these are also no real options. We can for example intercept all calls that go into the EL runtime by proxying all EL calls, but this has almost all of the issues as a custom ELResolver. Darn! -
Servlet Filter?
But what’s wrong with a plain old Servlet Filter which escapes HTML special tags afterwards? The issue with a Servlet Filter is that it can’t possibly see the difference between legitimate and injected markup. The Filter Either escapes all markup (including your own) or nothing (which renders it useless). After the JSP has been executed, you’ll end up with HTML. If there is an XSS attack, you are simply too late when you use a Servlet Filter. So, it has to do with timing. Let’s step back. -
Object graph XSS filtering!
There are two issues with most solutions presented.- Timing: The solution is too early or too late, making it useless or wrong.
- no. executions: The solution has the risk of escaping the variable more than once, making it wrong and unsafe.
So, what’s the best point in the request processing lifecycle to do the escaping? It turns out that just before the JSP is executed is the ideal moment. It’s ideal, because you’re not too early, so you won’t notice anything in your Java code. It’s also ideal, since you have full control over execution, making it easier to execute once and only once.
Object graph XSS filtering
The graph walker sounds like a solution, however, it’s a difficult one to implement.
The reason is the flexibility of our MVC framework. It’s allowed to pass arbitrary object graphs to the JSP. This is an issue, since you can’t just iterate over all attributes and escape them. For example, some attributes may be collections, maps or domain objects, containing possibly unsafe strings.
So we need an object walker. What features should it have?
- Cycle detection, to prevent infinite loops.
- Ability to modify arbitrary objects, either using reflection (POJO’s) or API (Collections).
Implementation sources
A hack and slash implementation of this solution is attached. What do you guys think of it? Does it look like a workable solution?
Ps. I’m aware of the fact that I haven’t implemented any pattern or followed any best practice. It’s just a simple PoC.

