A note about an HTML escaping gotcha in JSTL which can lead to XSS security problems.

Imagine you have a JSP page in which you want to construct a URL, with JSTL, using a string passed into the page. My particular case was pre-constructing a search query. So you want a final HTML construct which looks like:

<a href="/myapp/search?q=searchquery">Do Search</a>

Where "searchquery" bit comes from a parameter passed into the JSP page. You know you need to escape the searchquery to prevent XSS. Luckily the JSTL tag <c:out> automatically does HTML escaping for you, job done. You can just do:

<a href="/myapp/search?q=<c:out value='${searchquery}'/>">Do Search</a>

This will escape searchquery and all is well. Err, except you're not constructing the URL properly, you should be using the <c:url> JSTL tag to ensure the right appcontext is being used. So you change the code to look like:

The following code fragment DOES NOT do HTML escaping of the searchquery parameter. So the resulting URL can be an entry point for XSS security problems.

XSS Vulnerable Code
<a href="<c:url value='/search?q=${searchquery}'/>">Do Search</a>

Notice that the <c:out> is replaced by a ${} construct. This is because you're already in a JSTL tag, so you don't need (and can't nest) the <c:out> and, crucially, ${} doesn't do any HTML escaping.

To get round this problem, but still have <c:url> construct your correct context path, you have two options (probably more, but these are the two I found).

  1. the URL construction can be broken into two parts, use to make the main part of the URL, and use to add the parameters on the end. This gives a final working code fragment like this:
    <a href="<c:url value='/search'/>?q=<c:out value='${searchquery}'/>">Do Search</a>
  2. HTML encode the parameter into a new page variable, and use that in your <c:url> constructs, something like:
    <c:set var="foo"><c:out value="${searchquery}"></c:set>
    ...
    <a href="<c:url value='/search?q=${foo}'/>">Do Search</a>

Previous Post Next Post

© Me. Best viewed with a sense of humour and a beer in hand.