How do I escape a string inside JavaScript code inside an onClick handler?

JavascriptHtmlStringEscaping

Javascript Problem Overview


Maybe I'm just thinking about this too hard, but I'm having a problem figuring out what escaping to use on a string in some JavaScript code inside a link's onClick handler. Example:

<a href="#" onclick="SelectSurveyItem('<%itemid%>', '<%itemname%>'); return false;">Select</a>

The <%itemid%> and <%itemname%> are where template substitution occurs. My problem is that the item name can contain any character, including single and double quotes. Currently, if it contains single quotes it breaks the JavaScript code.

My first thought was to use the template language's function to JavaScript-escape the item name, which just escapes the quotes. That will not fix the case of the string containing double quotes which breaks the HTML of the link. How is this problem normally addressed? Do I need to HTML-escape the entire onClick handler?

If so, that would look really strange since the template language's escape function for that would also HTMLify the parentheses, quotes, and semicolons...

This link is being generated for every result in a search results page, so creating a separate method inside a JavaScript tag is not possible, because I'd need to generate one per result.

Also, I'm using a templating engine that was home-grown at the company I work for, so toolkit-specific solutions will be of no use to me.

Javascript Solutions


Solution 1 - Javascript

In JavaScript you can encode single quotes as "\x27" and double quotes as "\x22". Therefore, with this method you can, once you're inside the (double or single) quotes of a JavaScript string literal, use the \x27 \x22 with impunity without fear of any embedded quotes "breaking out" of your string.

\xXX is for chars < 127, and \uXXXX for Unicode, so armed with this knowledge you can create a robust JSEncode function for all characters that are out of the usual whitelist.

For example,

<a href="#" onclick="SelectSurveyItem('<% JSEncode(itemid) %>', '<% JSEncode(itemname) %>'); return false;">Select</a>

Solution 2 - Javascript

Depending on the server-side language, you could use one of these:

.NET 4.0

string result = System.Web.HttpUtility.JavaScriptStringEncode("jsString")

Java

import org.apache.commons.lang.StringEscapeUtils;
...

String result = StringEscapeUtils.escapeJavaScript(jsString);

Python

import json
result = json.dumps(jsString)

PHP

$result = strtr($jsString, array('\\' => '\\\\', "'" => "\\'", '"' => '\\"', 
                                 "\r" => '\\r', "\n" => '\\n' ));

Ruby on Rails

<%= escape_javascript(jsString) %>

Solution 3 - Javascript

Use hidden spans, one each for each of the parameters <%itemid%> and <%itemname%> and write their values inside them.

For example, the span for <%itemid%> would look like <span id='itemid' style='display:none'><%itemid%></span> and in the javascript function SelectSurveyItem to pick the arguments from these spans' innerHTML.

Solution 4 - Javascript

If it's going into an HTML attribute, you'll need to both HTML-encode (as a minimum: > to &gt; < to &lt and " to &quot;) it, and escape single-quotes (with a backslash) so they don't interfere with your javascript quoting.

Best way to do it is with your templating system (extending it, if necessary), but you could simply make a couple of escaping/encoding functions and wrap them both around any data that's going in there.

And yes, it's perfectly valid (correct, even) to HTML-escape the entire contents of your HTML attributes, even if they contain javascript.

Solution 5 - Javascript

Try avoid using string-literals in your HTML and use JavaScript to bind JavaScript events.

Also, avoid 'href=#' unless you really know what you're doing. It breaks so much usability for compulsive middleclickers (tab opener).

<a id="tehbutton" href="somewhereToGoWithoutWorkingJavascript.com">Select</a>

My JavaScript library of choice just happens to be jQuery:

<script type="text/javascript">//<!-- <![CDATA[
jQuery(function($){
   $("#tehbutton").click(function(){
        SelectSurveyItem('<%itemid%>', '<%itemname%>');
        return false;
   });
});
//]]>--></script>

If you happen to be rendering a list of links like that, you may want to do this:

<a id="link_1" href="foo">Bar</a>
<a id="link_2" href="foo2">Baz</a>

<script type="text/javascript">
   jQuery(function($){
        var l = [[1,'Bar'],[2,'Baz']];
        $(l).each(function(k,v){
           $("#link_" + v[0] ).click(function(){
                SelectSurveyItem(v[0],v[1]);
                return false;
           });
        });
   });
 </script>

Solution 6 - Javascript

Another interesting solution might be to do this:

<a href="#" itemid="<%itemid%>" itemname="<%itemname%>" onclick="SelectSurveyItem(this.itemid, this.itemname); return false;">Select</a>

Then you can use a standard HTML-encoding on both the variables, without having to worry about the extra complication of the javascript quoting.

Yes, this does create HTML that is strictly invalid. However, it is a valid technique, and all modern browsers support it.

If it was my, I'd probably go with my first suggestion, and ensure the values are HTML-encoded and have single-quotes escaped.

Solution 7 - Javascript

Declare separate functions in the <head> section and invoke those in your onClick method. If you have lots you could use a naming scheme that numbers them, or pass an integer in in your onClicks and have a big fat switch statement in the function.

Solution 8 - Javascript

Use the Microsoft Anti-XSS library which includes a JavaScript encode.

Solution 9 - Javascript

First, it would be simpler if the onclick handler was set this way:

<a id="someLinkId"href="#">Select</a>
<script type="text/javascript">
  document.getElementById("someLinkId").onClick = 
   function() {
      SelectSurveyItem('<%itemid%>', '<%itemname%>'); return false;
    };

</script>

Then itemid and itemname need to be escaped for JavaScript (that is, " becomes \", etc.).

If you are using Java on the server side, you might take a look at the class StringEscapeUtils from jakarta's common-lang. Otherwise, it should not take too long to write your own 'escapeJavascript' method.

Solution 10 - Javascript

Any good templating engine worth its salt will have an "escape quotes" function. Ours (also home-grown, where I work) also has a function to escape quotes for javascript. In both cases, the template variable is then just appended with _esc or _js_esc, depending on which you want. You should never output user-generated content to a browser that hasn't been escaped, IMHO.

Solution 11 - Javascript

I have faced this problem as well. I made a script to convert single quotes into escaped double quotes that won't break the HTML.

function noQuote(text)
{
    var newtext = "";
    for (var i = 0; i < text.length; i++) {
        if (text[i] == "'") {
            newtext += "\"";
        }
        else {
            newtext += text[i];
        }
    }
    return newtext;
}

Solution 12 - Javascript

Is the answers here that you can't escape quotes using JavaScript and that you need to start with escaped strings.

Therefore. There's no way of JavaScript being able to handle the string 'Marge said "I'd look that was" to Peter' and you need your data be cleaned before offering it to the script?

Solution 13 - Javascript

I faced the same problem, and I solved it in a tricky way. First make global variables, v1, v2, and v3. And in the onclick, send an indicator, 1, 2, or 3 and in the function check for 1, 2, 3 to put the v1, v2, and v3 like:

onclick="myfun(1)"
onclick="myfun(2)"
onclick="myfun(3)"

function myfun(var)
{
    if (var ==1)
        alert(v1);

    if (var ==2)
        alert(v2);

    if (var ==3)
        alert(v3);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrmeadorView Question on Stackoverflow
Solution 1 - JavascriptDuncan SmartView Answer on Stackoverflow
Solution 2 - JavascriptVitalii FedorenkoView Answer on Stackoverflow
Solution 3 - JavascriptShyam Kumar SundarakumarView Answer on Stackoverflow
Solution 4 - JavascriptDanView Answer on Stackoverflow
Solution 5 - JavascriptKent FredricView Answer on Stackoverflow
Solution 6 - JavascriptDanView Answer on Stackoverflow
Solution 7 - JavascriptmoonshadowView Answer on Stackoverflow
Solution 8 - JavascriptblowdartView Answer on Stackoverflow
Solution 9 - JavascriptAlexandre VictoorView Answer on Stackoverflow
Solution 10 - JavascriptlivingtechView Answer on Stackoverflow
Solution 11 - JavascriptStarbuck JohnsonView Answer on Stackoverflow
Solution 12 - JavascriptSteve PerksView Answer on Stackoverflow
Solution 13 - JavascriptAhmedGamalView Answer on Stackoverflow