Matt RaibleMatt Raible is a Java Champion and Developer Advocate at Okta. developer.okta.com

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: AngularJS, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Java Web Frameworks and XSS

In preparation for my talk at OSCON next week, I've been doing some research on cross-site scripting and how good Java web frameworks handle it. I'm disappointed to report that the handling of XSS in Java web frameworks is abysmal. First of all, the JSP EL doesn't bother to handle XSS:

With JSP 2.0 you can use the following to emit the description of a "todo" item:
${todo.description}
That's pretty nice. What happens when someone has entered a description like this?
<script type="text/javascript">alert('F#$@ you!');</script>
Well, it executes the JavaScript and pops up a nice little message to you.
...
My question is this: Why in the world did the expert group on the JSP 2.0 JSR decide to make not escaping XML content the default for EL expressions, when they made the opposite decision for c:out?

(Emphasis mine) If a company/developer wants to make sure their JSP-based code is not susceptible to XSS, they have two choices (as I see it):

  • Do lots of code review to make sure <c:out> is used instead of ${}.
  • Hack the jsp-compiler/el-engine to escape XML by default.

The good news is #2 doesn't seem to be that hard. I pulled down commons-el yesterday, added a hack to escape XML, re-jarred and put it in Tomcat 5.0.25's classpath. This actually worked and I was impressed it was so easy. However, when I looked at Tomcat 6, commons-el is no longer used and now there's a "jasper-el.jar" in the lib directory. I don't mind modifying another library, but what's the difference between jasper-el and commons-el?

Of course, the whole problem with JSP EL could be solved if Tomcat (and other containers) would allow a flag to turn on XML escaping by default. IMO, it's badly needed to make JSP-based webapps safe from XSS.

On a related note, there's a couple of web frameworks that I've found to be susceptible to XSS: namely Spring MVC and Struts 2. For Spring MVC, its <form:input> and <form:errors> tags are vulnerable. For Struts 2, OGNL expressions are evaluated, which is way worse than XSS and actually allows you to shutdown the JVM by putting %{@java.lang.System@exit(0)}" in a text field.

Even though it was surprising for me to see the issues with Struts 2 and Spring MVC, I'm somewhat glad they exist. If I hadn't discovered them, I might blissfully think that Java web frameworks aren't susceptible to XSS. However, it appears they're not only susceptible, but no one is really thinking about XSS when developing these framework. To further prove that theory, the Spring MVC and Struts 2 teams are aware of these issues, have been for quite some time - yet they've done nothing in the form of releasing upgrades or patches.

Seems kinda strange doesn't it?

Posted in Java at Jul 19 2007, 10:16:15 AM MDT 26 Comments
Comments:

In my opinion, no, it doesn't seem strange. All the frameworks have some method for escaping the data, but making ${todo.description} return escaped html shouldn't be the default. In some cases, you will have a site where the description is only entered via a backend, WYSIWYG form, as part of some kind of CMS that only trustworthy administrators have access to. In that case, you don't want to have the data escaped. For example, in Rails you would do <%= todo.desciption %>, which would give you the unescaped data, but I don't think it would be fair to say that Rails "doesn't bother to handle XSS". It just doesn't handle it by default. Since in rails, the code between the <%= %> is just ruby, you wrap it in the h method, like <%=h todo.description %>.

Posted by Paul Barry on July 19, 2007 at 11:21 AM MDT #

Surely, as a best practice, you only use c:out for backwards compatibility?

Posted by John on July 19, 2007 at 11:21 AM MDT #

Is your criticism of Struts fair? AFAIK the current issue was only raised 3 days ago here - apparently it needs a release of XWork first (which is done) and a Struts2 release - which is on the agenda.

Also IMO the Struts team has a good history of fixing vulnerabilities - Struts 1.2.8 and Struts 1.2.9 releases were both primarily to fix those types of issues.

re: EL and Tomcat 6 As part of JSR 245 (Servlet 2.5 / JSP 2.1) the expression language was separated out from the Servlet Spec into its own specification document as part of the process to provide a Unified Expression Language for both JSP and JSF. Tomcat 6 now ships with an implementation of the Unified EL (which btw has no Servlet/JSP/JSF dependency) - the el-api.jar in Tomcat is the Spec and the jasper-el jar is the implementation of the Unfied EL.

Posted by Niall on July 19, 2007 at 03:46 PM MDT #

I don't want to hijack this thread, but in relation to XSS and security, Gavin and Seam have come down firmly against the standard 'remember me' functionality:

Matt,
Given this feature is in Appfuse, is the implementation completely secure?

Cheers
Charles

Posted by Charles Crouch on July 19, 2007 at 04:35 PM MDT #

Niall - I agree that the Struts team has done a good job of letting the community know that there's a problem and they're working on fixing it. However, there have been no public announcements about this (potentially) huge security hole. All I'm asking for is a blog post from a member of the developer team to acknowledge the issue and provide more transparency.

As far as commons-el vs. jasper-el, does that mean that commons-el is only for JSP 2.0 and it won't be upgraded to support the Unified EL? What's the point of commons-el if Tomcat is providing their own implementation?

Charles - I'm not too concerned about someone hijacking my remember me cookie. However, I also know how to provide a better implementation than what Acegi provides. So if it ever gets hacked, I'll start writing that implementation. ;-)

Posted by Matt Raible on July 19, 2007 at 06:07 PM MDT #

Everything about that issue has been discussed on a public list - can't see how it can be any more transparent than that? In the past where we have been privately informed of vulnerabilities then we've kept quiet about it until we've had a fix version released. Theres two possible approaches to this 1) Warn everyone ASAP or 2) Publicize it as little as possible until a fix is available. The problem with 1) is that it also informs malicious users of how to attack sites built on Struts - something Struts Users may not appreciate when there isn't a fix available.

On commons-el vs. jasper-el - basically the Tomcat team got pissed off with Commons and have been in-housing components they used to depend on from Commons. Personally I don't agree with it - and don't understand why they didn't continue development in commons - a number of Tomcat devs. had access and I'm sure any others that wanted it would be welcomed. Its a policy I only becamse aware of early this year, and my attemt to lure them back didn't get any reaction. The good news is though that their Unified EL implementation is now available on the standard maven repo - thanks to Filip Hanik - so its available independantly of the rest of Tomcat. The bad news is that Jacob Hookom who donated the Unified EL impl to Tomcat has now abandonned it - taking it over to Glassfish and it doesn't look like anyone else from Tomcat has picked it up.

Posted by Niall on July 19, 2007 at 06:57 PM MDT #

While I agree that the default should be escaping, EL was likely designed with JSTL and its functions in mind:

    ${fn:escapeXml(string)}

But, it probably would be better if it had been the inverse:

    ${fn:dontEscapeXml(string)}

Posted by Dave on July 19, 2007 at 10:47 PM MDT #

Niall, thought I should comment here-- the fact that commons-el sucked so horribly is actually what got me involved in JSF in the first place around 2004. It was a clean room impl of what was JSF-EL (remember 1.1 had it's own as part of the API). While joining JSF 1.2 EG late in the process, I was then participating in the WebTier EG for Java EE 5 and I ended up writing the Unified EL RI. Because of whatever legal hub bub, I still share intellectual rights to the code I wrote and contributed to the Tomcat project and even worked on the JSP 2.1 implementation-- while Sun was still modifying the JSP 2.1 and EL specs. Since then, the kind folks at Apache have picked up the torch and finished the work and all the discussion about bringing anything over to commons I've stayed out of-- I didn't have the history with Tomcat or Apache in general to offer an opinion on the matter.

Posted by Jacob Hookom on July 19, 2007 at 11:51 PM MDT #

Just for the record: Wicket components and <wicket:message> markup escapes xml (and html) by default. You have to explicity call setEscapeModelStrings(false) on a component to change this bahaviour.

Posted by Janos Cserep on July 20, 2007 at 02:23 AM MDT #

Facelets also automatically escapes any inline EL content such that if you did want to output the literal value, you'd have to use an h:outputText and specifically say not to escape the content. There's more that could be done to prevent XSS, but the Facelets community thought this default behavior was more than appropriate.

Posted by Jacob Hookom on July 20, 2007 at 07:14 AM MDT #

Just trying this out. Is this a cause for concern? Hello to you!

Posted by Roshan Shrestha on July 20, 2007 at 08:54 AM MDT #

That's good to know Jacob. I like your decision. Do you think it's possible to lobby the Tomcat folks to allow a flag for jasper-el that provides the same behavior? All I'm looking for is something similar to trim spaces, which isn't part of the JSP spec AFAIK.

Roshan: Yes, Roller has some XSS issues when you have full HTML turned on for comments. I believe these are fixed in the 3.1 release (which I haven't upgraded to). Regardless, I still want full HTML functionality and since I get e-mail notifications for every comment - I'm not too concerned. I can delete the comment pretty quickly if it's malicious. However, it would be nice to auto-moderate comments with "script" in them, or something like that.

Posted by Matt Raible on July 20, 2007 at 09:35 AM MDT #

Matt, it wouldn't necessarily be a feature that's EL-based, but within the compiled JSP. What Facelets does is evals everything as normal, but if it's a Text fragment doing the output, it takes the EL results and escapes it before outputting. So really, you'd be looking at a compilation flag within Jasper such that the resulting class files are built to do escaping of template EL fragments.

Posted by Jacob Hookom on July 20, 2007 at 09:43 AM MDT #

This was eye opening: %{@java.lang.System@exit(0)} Maybe a better version of it would be something like: %{@java.lang.Runtime@exec("rm -rf /")}

Posted by Bryan Noll on July 20, 2007 at 10:09 AM MDT #

Some of the frameworks have also been using convention over configuration with their URI patterns such that you could do '/shale/beans/applicationScope/clear'-- I believe WW also has similar issues but would be the fault of the developer since WW forces an action layer to be written and acts as a point of security.

Posted by Jacob Hookom on July 20, 2007 at 11:08 AM MDT #

Well, for those keeping records, Tapestry has been doing this for the last 6 years or so ;) But anyway, getting defaults right is really important these days - and it's not as easy as one might think... i mean, sometimes, what initially seems intuitive is proven wrong by practice.

Posted by Andreas Andreou on July 20, 2007 at 12:09 PM MDT #

I ran across this page recently which has some good advice regarding the Spring MVC tags: http://shh.thathost.com/secadv/spring-form-xss/.

Posted by Mark Helmstetter on July 22, 2007 at 12:24 AM MDT #

Isn't there any way we can just replace the request parameters in say a Struts 2 interceptor with their HTML escaped values? I know it doesn't really make sense and that the parameter map is unmodifiable but is there any progress on this approach?

Posted by Zarar Siddiqi on November 15, 2007 at 11:13 AM MST #

Hi Matt, use followingh in your web.xml file for Spring MVC (it should be the default) <context-param> <param-name>defaultHtmlEscape</param-name> <param-value>true</param-value> </context-param> Thanks, Shoaib

Posted by Shoaib Akhtar on December 10, 2007 at 12:53 PM MST #

Shoaib - this works for Spring's JSP tags, but not for JSP EL. Spring doesn't control how JSP EL is interpreted.

Posted by Matt Raible on December 10, 2007 at 04:54 PM MST #

I'm actually very relieved to see that escaping XML is NOT the default for el expressions. While you have a very good point about how it could save you from XSS, from a programming standpoint, I end up using more variables from the underlying application than I do from user input - a good example is a SQL query stored as a context parameter in my web.xml. I explicitly trust this parameter - and I KNOW I don't want to escape the XML special characters (makes databases grumpy). If you're using JSTL 1.1, what you really want to do is something like: ${fn:escapeXml(param.untrustedInput)} ... extra typing, but easier to do programmatically than ${fn:dontModify(param.escapedInput)}

Posted by Pete Nelson on May 29, 2008 at 07:30 PM MDT #

"The good news is #2 doesn't seem to be that hard. I pulled down commons-el yesterday, added a hack to escape XML, re-jarred and put it in Tomcat 5.0.25's classpath."

Hi Matt, I have struts problems with my app since it doesnt do anything for handling of XSS. I was wondering if you still have that jar file you fixed and re-jarred to make ${} to escape xml, and if I can have it to fix my application please.

Posted by Manny on October 15, 2009 at 03:13 PM MDT #

@Manny - it's been a couple years and unfortunately I don't have the patched JAR anymore. The good news is I did submit an issue and patch to Tomcat's issue tracker.

Posted by Matt Raible on October 15, 2009 at 09:21 PM MDT #

@Matt Thank you for you prompt response. I will look at the patch you pointed out.

Posted by Manny on October 16, 2009 at 06:54 AM MDT #

Nice to hear that other developers use the same technique with us.

"Hack the jsp-compiler/el-engine to escape XML by default. "

Unfortunately, there is no other way for such a basic requirement.

There is only one, write a escapeThis(String) function and add it to every JSP expression, but this is not a good and clean solution.

We are using WebSphere and we had to touch JSP engine codes to escape HTML. Rarely you may need to bypass escaping, we did it by using a method like unescapeThis(String) in expressions and injecting this to the engine.

Another basic requirement is to ignore "null" string when displaying expressions. After 10 years, still JSP expressions prints null string to the page. I don't know how many developers want to see "null" in JSP pages. I'm sure 99.99 of JSP programmers don't want to see "null" string in page.

Posted by Ibrahim Levent on April 16, 2010 at 01:45 AM MDT #

[Trackback] Way back in 2007, I wrote about Java Web Frameworks and XSS . My main point was that JSP EL doesn't bother to handle XSS . Of course, the whole problem with JSP EL could be solved if Tomcat (and other containers) would allow a flag to turn on X...

Posted by Raible Designs on February 28, 2011 at 03:13 PM MST #

Post a Comment:
  • HTML Syntax: Allowed