Issue Details (XML | Word | Printable)

Key: SPR-1754
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Rob Harrop
Reporter: Adam Murray
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Spring Framework

javaScriptEscape in Spring tags doesn't escape </script>

Created: 02/Mar/06 08:59 PM   Updated: 11/Apr/06 09:33 AM   Resolved: 11/Apr/06 09:33 AM
Component/s: SpringWEB
Affects Version/s: None
Fix Version/s: 2.0 M4, 1.2.8

Time Tracking:
Not Specified

Environment: issue is independent of environment


 Description  « Hide

Browsers parse the </script> tag even if it appears inside a string literal in javascript. In other words, the following HTML:
<html>
<body>
<script>
document.write("</script>");
</script>
</body>
</html>
is invalid because the </script> inside the document.write() will be interpreted as the end of the javascript.

Spring's javaScriptEscape should handle escaping the </script> tag to prevent a web page from breaking when someone sends </script> as input. Here's a jsp that demonstrates the problem:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<html>
<body id="body">
</body>
<script type="text/javascript">
function drawTextInput(value) { var input = document.createElement("input"); input.type = "text"; input.value = value; document.getElementById("body").appendChild(input); }
drawTextInput('<c:out value="${param.input}"/>');
drawTextInput('<spring:message text="${param.input}" javaScriptEscape="true"/>');
</script>
</html>

If you deploy and browse to this JSP, you can control the text field values with a request parameter named input, like /jstest.jsp?input=foo
I put in the <c:out> and <spring:message> versions to show the different behaviors between these two tags. I want the text input value to match the user input, but <c:out> escapes it, so I need to use something like the spring tag with javaScriptEscaping. But you'll notice that if you set input=</script>, it breaks the page. In case you're wondering why I would do this in a real application, I have some dynamic forms with a lot of interactive functionality, and most of the form HTML is conditionally rendered by javascript based on user interactions.

I took a look at the source code, and the fix is very easy. I just added the following condition in JavaScriptUtils.javaScriptEscape()
else if (c == '/') { filtered.append("\\/"); }

This will replace '/' with '\/', which is for the most part equivalent to '/' but has the nice side effect that <\/script> will not be interpreted as the end script tag in string literals. You can verify the fix with the JSP above, but here's another one you can use to verify that also demonstrates the new replacement operation does not change the interpreted value of the string literals:
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<% String endScript = "</script>"; %>
<html>
<body>
<script type="text/javascript">
alert("<spring:escapeBody javaScriptEscape="true"><%= endScript %></spring:escapeBody>");
alert("/" == "\/");
alert("</"+"script>" == "<spring:escapeBody javaScriptEscape="true"><%= endScript %></spring:escapeBody>");
</script>
</body>
</html>



Henri Yandell added a comment - 07/Mar/06 05:08 PM

Hi Adam,

I had a play with this with a work colleague and after digging into it a bit we realised that there is a simple (and old ) work-around.

Your problem is that the HTML parser doesn't want to understand the syntax of the scripting implementation, so if you comment out the javascript it won't fall over on the closing script tag.

ie: (hoping that Jira escapes this nicely)

<script type="text/javascript">
<!--
drawTextInput('<spring:message text="${param.input}" javaScriptEscape="true"/>');
-->
</script>

This is an old work-around from the JScript/JavaScript days of IE3 and NN4 (or versions around that time).


Adam Murray added a comment - 07/Mar/06 05:57 PM

Thanks for the info, Henri.
That's a nice workaround, but it could creates some other problems. If for some reason you need to include the characters --> anywhere in the javascript, even in a string literal, it will end the comment. This script breaks in firefox:

<script>
<!--
document.write("-->");
document.write("</script>");
-->
</script>

I know that's contrived and unlikely to happen, but the point remains that there are still situations where this fix will not work.

But there's a bigger problem. In xhtml documents, some browsers will respect the comment and ignore all the javascript. See http://developer.mozilla.org/en/docs/Properly_Using_CSS_and_JavaScript_in_XHTML_Documents#Use_of_Comments_Inside_Inline_style_and_script for details.

So your suggestion is an acceptable temporary workaround for straight HTML, but I think the long term fix should be to address this issue in Spring.