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?
Cross-site scripting (XSS) is one of the most critical attacks on web security. Preventing the XSS attack is a challenge in a Spring application. Spring provides some help, but we need to implement extra code for complete protection. In this tutorial, we'll use the available Spring Security features, and we'll add our own XSS filter.
XSS is a common type of injection attack. In XSS, the attacker tries to execute malicious code in a web application. They interact with it through a web browser or HTTP client tools like Postman. There are two types of XSS attacks:
Non-persistent XSS is also known as reflected cross-site vulnerability. It is the most common type of XSS. In this, data injected by attacker is reflected in the response. If you take a look at the examples we have shown above, the first XSS example was a non-persistent attack.
How to prevent XSS client-side in JavaScript. To escape user input in an HTML context in JavaScript, you need your own HTML encoder because JavaScript doesn't provide an API to encode HTML. Here is some example JavaScript code that converts a string to HTML entities: function htmlEncode(str){ return String(str).replace(/[^\w. ]/gi, function(c)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With