I'm working on preventing cross site scripting (XSS) in a Java, Spring based, Web application. I have already implemented a servlet filter similar to this example http://greatwebguy.com/programming/java/simple-cross-site-scripting-xss-servlet-filter/ which sanitizes all the input into the application. As an extra security measure I would like to also sanitize all output of the application in all JSPs. I have done some research to see how this could be done and found two complementary options.
One of them is the use of Spring's defaultHtmlEscape
attribute. This was very easy to implement (a few lines in web.xml), and it works great when your output is going through one of spring's tags (ie: message, or form tags). The other option I have found is to not directly use EL expressions such as ${...}
and instead use <c:out value="${...}" />
That second approach works perfectly, however due to the size of the application I am working on (200+ JSP files). It is a very cumbersome task to have to replace all inappropriate uses of EL expressions with the c:out
tag. Also it would become a cumbersome task in the future to make sure all developers stick to this convention of using the c:out
tag (not to mention, how much more unreadable the code would be).
Is there alternative way to escape the output of EL expressions that would require fewer code modifications?
Since Servlet 2.5/JSP 2.1 you could create a custom ELResolver
which does that. You can register it in ServletContextListener#contextInitialized()
.
@Override
public void contextInitialized(ServletContextEvent event) {
JspFactory.getDefaultFactory()
.getJspApplicationContext(event.getServletContext())
.addELResolver(new YourCustomELResolver());
}
In the ELResolver#getValue()
you could do the escaping job.
Your only problem is that you will be unable to display HTML there where it's allowed (i.e. already sanitized from malicious tags/attributes by kind of a whitelist so that you end up with innocent tags like Jsoup can do).
That said, I disagree the necessity to escape XSS during input by the Filter
as you mentioned in 1st paragraph of the question. You risk double-escaping. You only need to escape it at exactly that point where it can possibly harm, i.e. straight in the view side there where it's going to be inlined among HTML, the output. I recommend to get rid of that so-called XSS filter and concentrate you on fixing it in the view side by either using JSTL <c:out>
or fn:escapeXml()
(or a custom EL resolver, but that's definitely not the normal approach). The future code maintainers will be greatly thankful.
This blog post describes a custom ELResolver which escapes EL expression values of type String. Registering this custom ELResolver will cause it to escape the output of all EL expressions. In the exceptional cases where a JSP must programmatically output HTML, you require a mechanism that does not involve an EL expression, such as a custom tag or a scriptlet:
<%= "Java expression hopefully returning safe HTML" %>
I agree you shouldn't have to use c:out around every variable.
I wrote a blog describing why at http://tech.finn.no/2011/04/08/xss-protection-whos-responsibility/
It touches on much that is said here.