36

I have a user form. If the user types in a string with ' or " as part of it I have no problem. The form is submitted and saved correctly to the database. My problem is when I reload the page (all entries can be modified and are loaded into a list in the JSP before being displayed). On loading the page I get an error saying:

missing ) after argument list 'Caroline's message', \n

What do I need to do to escape this string for displaying it on the frontend?

Here is the code I am using on the frontend to read in the data and store it in a JavaScript object. I am not fully sure where I need to escape. The field causing the problem is c.getComName:

communications[<%=i%>][1] = new CommObject('<%=c.getComId()%>', '<%=c.getComName()%>');

UPDATED WITH HTML GENERATED:

communications[0][1] = new CommObject('101', 'Caroline's Message');
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Caroline
  • 969
  • 3
  • 16
  • 22
  • What do you mean by messed up? In what way are those characters messed up? – Gumbo Sep 24 '09 at 10:08
  • Sorry, further investigation revealed that my problem is not in submitting the form but on retrieving the data again after submission, see updated question – Caroline Sep 24 '09 at 10:17
  • Can you show the generated HTML? – David Rabinowitz Sep 24 '09 at 12:01
  • HTML added, I removed the second part of the question regarding jquery, after looking at the HTML this is the only place that has the ' in it so this is where I need it to be escaped. – Caroline Sep 24 '09 at 15:30

9 Answers9

49

I prefer to avoid scriptlets in the middle of my page and was having to use them (increasingly often) to escape strings when used in JavaScript code. I wanted an Expression Language (EL) way of escaping the strings. I created a very small custom taglib that I use for just this purpose:

Utilities.java:

package com.mycom.taglibs;

import org.apache.commons.lang.StringEscapeUtils;

public class Utilities {
    public static String escapeJS(String value) {
        return StringEscapeUtils.escapeJavaScript(value);
    }
}

mytaglib.tld:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">

  <description>My Tag Library</description>
  <display-name>Tag Utils</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>myt</short-name>

  <function>
    <description>
        JavaScript Escape function
    </description>
    <name>escapeJS</name>
    <function-class>com.mycom.taglibs.Utilities</function-class>
    <function-signature>java.lang.String escapeJS(java.lang.String)</function-signature>
  </function>
</taglib>

And, in the JSP page:

<%@ taglib prefix="myt" uri="/WEB-INF/mytaglib.tld" %>
The escaped string is: ${myt:escapeJS(variableHoldingTheString)}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RHSeeger
  • 16,034
  • 7
  • 51
  • 41
  • 12
    Thanks, this is good advice :) I would just add that you don't need the Utilities.java class. You can construct the taglib directly with StringEscapeUtils like so: org.apache.commons.lang.StringEscapeUtils java.lang.String escapeJavaScript(java.lang.String) – machinery Feb 07 '12 at 09:05
  • 1
    Updating @machinery's answer with new package and function name: `org.apache.commons.lang3.StringEscapeUtils java.lang.String escapeEcmaScript(java.lang.String)` However, I didn't use this answer because my taglib tag complained `The content of element type "taglib" must match "(tlibversion,jspversion?,shortname,uri?,info?,tag+)"` and I didn't know how to fix it. – Noumenon May 09 '18 at 17:12
24

Use the Apache StringEscapeUtils.escapeJavaScript function.

Escapes the characters in a String using JavaScript String rules.

Escapes any values it finds into their JavaScript String form.
Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)

So a tab becomes the characters '\\' and 't'.
Sanghyun Lee
  • 21,644
  • 19
  • 100
  • 126
Kevin Hakanson
  • 41,386
  • 23
  • 126
  • 155
  • Also, if this string is a URL (for example javascript:launchURL(<%=c.getComUrl()%>) you can combine this StringEscapeUtils.escapeJavaScript with URLEncoder.encode to produce a javascript-safe URL. – piepera Dec 20 '11 at 18:29
  • 12
    Just note that this has been changed to `StringEscapeUtils.escapeEcmaScript(String)` in commons lang 3.x+ – rcl Feb 25 '13 at 19:08
  • 1
    It also converts any non-latin alphabetic symbol into its unicode sequence ("кириллица" -> "\\u043A\\u0438\\u0440\\u0438\\u043B\\u043B\\u0438\\u0446\\u0430"). The question was only about single quotes. – Mikhail Batcer Oct 23 '15 at 08:12
  • Another note, in newer versions of commons-lang3 this is marked as deprecated, in favor of the equivalent class from commons-text. – pioto Oct 04 '19 at 19:50
3

fn:escapeXml does not work in JavaScript. It replaces ' with #&0039; still causing an error when the JavaScript is executed.

Only escaping in the JavaScript manner is correct: \'

The Apache StringEscapeUtils.escapeJavaScript function does this for you. Creating a taglib for it greatly simplifies matters.

Madbreaks
  • 19,094
  • 7
  • 58
  • 72
Radboud
  • 81
  • 5
2

You can use the JSTL escape function fn:escapeXml() to get rid of anomalies caused due to single quotes(`). The following example demonstrates the difference.

For example:

<c:set var="string1" value="This is abc's first String."/>
<c:set var="string2" value="This is abc's second String."/>

<p>With escapeXml() Function:</p>
<p>string (1): ${fn:escapeXml(string1)}</p>

<p>Without escapeXml() Function:</p>
<p>string (2): ${fn:escapeXml(string2)}</p>

RESULT

string (1): This is abc s first String.

string (2): This is abc's second String.

Community
  • 1
  • 1
boniezuvyz
  • 99
  • 5
2

Also we have very nice solution from Spring:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<spring:message code="${propertyName}" javaScriptEscape="true"/>

So, issue from the question of this post can be resolved in this way:

communications[<%=i%>][1] = new CommObject('<spring:message code="${c.comId}" javaScriptEscape="true"/>', '<spring:message code="${c.comName}" javaScriptEscape="true"/> <%=c.getComName()%>');
  • 1
    I think this answer only works if `propertyName` points to a message in a MessageResource. For printing the actual text of propertyName, escaped, you want `text="${propertyName}"` instead. Very handy tag, though! I will use it a lot. – Noumenon May 09 '18 at 17:11
0

When you return the HTML from the CommObject class add in the \" instead of the ' and before the name (e.g. Caroline's message)

Like this: return "\"" + comName + "\"";

amischiefr
  • 4,750
  • 2
  • 29
  • 22
0

I have faced this problem while I was passing data from my servlet to my JSP then to my code Javascript to create JSON object so I need it ' but it's rendered like &#39 ; which can't be in the JSON object so to fixed I had simply to change my JSP from writing ' to ` the 6 key and it worked fine.

L3xpert
  • 1,109
  • 1
  • 10
  • 19
-1

That's strange.

What about:

'<%=c.getComName().replaceAll("\\'","\\\\'")%>'

If that works, you just have to figure out how to add the \".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • it actually doesn't fix it which is a surprise to me! – Caroline Sep 24 '09 at 15:50
  • :-o I guess you'll need to preprocess the name before delivering it back to the front end. :( – OscarRyz Sep 24 '09 at 16:28
  • 4
    Never ever write your own escaping code! You forgot for example to account for possible backslash characters in the original string. Use tried and tested code, like the mentioned `StringEscapeUtils` – David Balažic Oct 04 '16 at 20:29
-2

You could use JSP core tags:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>      
var jsVar = "<c:out value='${stringVariable}' />";
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nickc
  • 21
  • 1
  • 4
    There is a difference between escaping text for Javascript and for HTML/XML. Your answer addresses the latter but this question was asking for the former. Because c:out will produce HTML/XML entities which don't always work in JS code. – nickdos Oct 25 '12 at 00:02
  • You will be able to break the js context: "is extremely easy to switch into an execution context with characters including (but not limited to) semi-colon, equals, space, plus, and many more, so use with caution." from https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet – Tarion Apr 23 '14 at 15:32
  • Yup, injecting `` in the ` – eel ghEEz Aug 30 '19 at 16:46