views:

20748

answers:

10

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 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. 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... Your input is much appreciated.

Edit: 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.

+1  A: 

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.

moonshadow
A: 

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

blowdart
+2  A: 

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.

Dan
+1  A: 

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 (i.e. " becomes \" ...). 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 to long do write your own 'escapeJavascript' method.

Alexandre Victoor
+7  A: 

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 JS lib 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>
Kent Fredric
+1  A: 

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.

Dan
personally I think that technique is a bad way to associate data with nodes. http://noteslog.com/metaobjects/ is a slightly advanced technique, but it leaves you with a valid page and results in the same data.
Kent Fredric
I completely agree that it's a little bit of a filthy solution, but it can certainly make some tricky things significantly easier. It's definitely a niche fix, though ;)The 'metaobject' technique is an interesting one, although a bit hacky in itself, I can see how it would be useful.
Dan
+11  A: 

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 knowledge you can create a robust JSEncode function for all chars that are out of the usual whitelist.

E.g.

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

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?

Steve Perks
A: 

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.

livingtech
+1  A: 

Use a hidden spans, one each for the 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.

Shyam
I know my answer is too late. :)Nevertheless it would help someone later.
Shyam