252

I'm outputting values from a database (it isn't really open to public entry, but it is open to entry by a user at the company -- meaning, I'm not worried about XSS).

I'm trying to output a tag like this:

<a href="" onclick="DoEdit('DESCRIPTION');">Click Me</a>

DESCRIPTION is actually a value from the database that is something like this:

Prelim Assess "Mini" Report

I've tried replacing " with \", but no matter what I try, Firefox keeps chopping off my JavaScript call after the space after the word Assess, and it is causing all sorts of issues.

I must bemissing the obvious answer, but for the life of me I can't figure it out.

Anyone care to point out my idiocy?

Here is the entire HTML page (it will be an ASP.NET page eventually, but in order to solve this I took out everything else but the problem code)

<html>
    <body>
        <a href="#" onclick="DoEdit('Preliminary Assessment \"Mini\"'); return false;">edit</a>
    </body>
</html>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matt Dawdy
  • 19,247
  • 18
  • 66
  • 91
  • 3
    It's a good idea to make your `onclick` event attachment unobtrusive and to move all of your database information into a data island. Things will be cleaner and you'll actually get some sort of syntax error when your strings are escaped wrong. – Justin Johnson Jan 05 '10 at 04:40
  • 1
    Possible duplicate of *[How do I escape a string inside JavaScript code inside an onClick handler?](http://stackoverflow.com/questions/97578/how-do-i-escape-a-string-inside-javascript-code-inside-an-onclick-handler)*. – Peter Mortensen May 04 '15 at 17:19
  • You can also use escape("string") and unescape("string") jquery methods – Abhiram Apr 04 '19 at 16:31

13 Answers13

242

You need to escape the string you are writing out into DoEdit to scrub out the double-quote characters. They are causing the onclick HTML attribute to close prematurely.

Using the JavaScript escape character, \, isn't sufficient in the HTML context. You need to replace the double-quote with the proper XML entity representation, &quot;.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aaron
  • 4,194
  • 2
  • 19
  • 19
  • 1
    Right, but wouldn't that be this? edit I tried that, and it is still screwing up. This has got to be a simple WTF but for the life of me, I can't see it. – Matt Dawdy Jan 05 '10 at 04:35
  • Is there any built-in JavaScript function that would escape the double quotes ? Apart from 'quo"'.replace('"', '"') I can't find anything. – kevin Aug 18 '10 at 14:39
  • 4
    It's not a javascript issue, it's an HTML/XML encoding issue: you can't have double-quote characters inside an attributes value w/o escaping them... otherwise browsers/parsers think you're ending the attribute value declaration. – Aaron Aug 21 '10 at 07:09
  • 30
    example replacement code: `'mystring'.replace(/"/g, '"');` – Joshua Burns Mar 28 '13 at 22:53
  • 3
    in the previous comment there is an extra quote. The code that works is 'mystring'.replace(/'/g, '"'); – Agustin Lopez Jan 13 '14 at 15:35
  • I know this is an old question, but why not simply use encodeURIComponent() / decodeURIComponent() -- to my knowledge they do exactly what you want and have been around since Armstrong walked on the moon or thereabouts i.e. all browsers support it. – Adergaard Aug 11 '16 at 17:36
  • @Adergaard, nope. Those are for a _third_ escape scheme used by HTTP in URLs. `encodeURIComponent('"') == '%22'` (URI [includes](http://stackoverflow.com/a/1984225/673991) URL). – Bob Stein Sep 17 '16 at 02:13
  • @BobStein-VisiBone Well, in my usecase it works perfectly. I have data-attributes that need to contain user generated text and when using my suggestion it works like a charm from mandarine chinese to danish with all 14 excalmation points used. – Adergaard Sep 20 '16 at 07:32
  • @AgustinLopez I don't see an extra quote in Joshua Burns' answer - just a double quote instead of a single quote. – Sean the Bean Oct 25 '17 at 16:29
115

&quot; would work in this particular case, as suggested before me, because of the HTML context.

However, if you want your JavaScript code to be independently escaped for any context, you could opt for the native JavaScript encoding:
' becomes \x27
" becomes \x22

So your onclick would become:
DoEdit('Preliminary Assessment \x22Mini\x22');

This would work for example also when passing a JavaScript string as a parameter to another JavaScript method (alert() is an easy test method for this).

I am referring you to the duplicate Stack Overflow question, How do I escape a string inside JavaScript code inside an onClick handler?.

Community
  • 1
  • 1
tsemer
  • 2,959
  • 3
  • 29
  • 26
  • 2
    Thank you! Yours is the more correct answer because it is native JavaScript regardless of context. – scarver2 Jul 30 '13 at 05:51
  • 2
    This is the correct answer, although in an HTML context using `"` will, of course, work. – Oliver Mar 11 '14 at 12:05
  • Note that `"` is required in input values, i.e., `` will not work. – thdoan Mar 31 '18 at 06:26
  • @10basetom naturally, JavaScript escaping only works in a JavaScript context, like event handlers (`onclick="..."`). The value of a `value` attribute is not being processed within a JavaScript context, only within an HTML context. – tsemer Apr 11 '18 at 13:58
  • 1
    replacement code: `'mystring'.replace(/"/g, '\\x22').replace(/'/g, '\\x27')` – chickens May 01 '18 at 16:33
34
<html>
    <body>
        <a href="#" onclick="DoEdit('Preliminary Assessment &quot;Mini&quot;'); return false;">edit</a>
    </body>
</html>

Should do the trick.

kristian
  • 22,731
  • 8
  • 50
  • 78
28

Folks, there is already the unescape function in JavaScript which does the unescaping for \":

<script type="text/javascript">
    var str="this is \"good\"";
    document.write(unescape(str))
</script>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rohtakdev
  • 956
  • 1
  • 13
  • 16
  • 3
    A combination of "escape"/"unescape" did what I needed. Thanks. – Luis R. Jan 06 '12 at 04:53
  • 11
    escape/unescape are deprecated. although encodeURI does more than just quotes. http://gotochriswest.com/blog/2011/05/23/escape-unescape-deprecated/ – chug2k Nov 21 '12 at 02:15
14

This is how I do it, basically str.replace(/[\""]/g, '\\"').

var display = document.getElementById('output');
var str = 'class="whatever-foo__input" id="node-key"';
display.innerHTML = str.replace(/[\""]/g, '\\"');

//will return class=\"whatever-foo__input\" id=\"node-key\"
<span id="output"></span>
Ronnie Royston
  • 16,778
  • 6
  • 77
  • 91
13

The problem is that HTML doesn't recognize the escape character. You could work around that by using the single quotes for the HTML attribute and the double quotes for the onclick.

<a href="#" onclick='DoEdit("Preliminary Assessment \"Mini\""); return false;'>edit</a>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dl.
  • 2,264
  • 1
  • 19
  • 22
  • 5
    Yikes. I was wondering why I naturally resorted to using ' for the attribute in the past. I just never delved into it all that deeply. Thanks. – Matt Dawdy Jan 05 '10 at 05:15
2

Please find in the below code which escapes the single quotes as part of the entered string using a regular expression. It validates if the user-entered string is comma-separated and at the same time it even escapes any single quote(s) entered as part of the string.

In order to escape single quotes, just enter a backward slash followed by a single quote like: \’ as part of the string. I used jQuery validator for this example, and you can use as per your convenience.

Valid String Examples:

'Hello'

'Hello', 'World'

'Hello','World'

'Hello','World',' '

'It\'s my world', 'Can\'t enjoy this without me.', 'Welcome, Guest'

HTML:

<tr>
    <td>
        <label class="control-label">
            String Field:
        </label>
        <div class="inner-addon right-addon">
            <input type="text" id="stringField"
                   name="stringField"
                   class="form-control"
                   autocomplete="off"
                   data-rule-required="true"
                   data-msg-required="Cannot be blank."
                   data-rule-commaSeparatedText="true"
                   data-msg-commaSeparatedText="Invalid comma separated value(s).">
        </div>
    </td>

JavaScript:

     /**
 *
 * @param {type} param1
 * @param {type} param2
 * @param {type} param3
 */
jQuery.validator.addMethod('commaSeparatedText', function(value, element) {

    if (value.length === 0) {
        return true;
    }
    var expression = new RegExp("^((')([^\'\\\\]*(?:\\\\.[^\'\\\\])*)[\\w\\s,\\.\\-_\\[\\]\\)\\(]+([^\'\\\\]*(?:\\\\.[^\'\\\\])*)('))(((,)|(,\\s))(')([^\'\\\\]*(?:\\\\.[^\'\\\\])*)[\\w\\s,\\.\\-_\\[\\]\\)\\(]+([^\'\\\\]*(?:\\\\.[^\'\\\\])*)('))*$");
    return expression.test(value);
}, 'Invalid comma separated string values.');
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dinesh Lomte
  • 569
  • 7
  • 5
2

If you're assembling the HTML in Java, you can use this nice utility class from Apache commons-lang to do all the escaping correctly:

org.apache.commons.lang.StringEscapeUtils
Escapes and unescapes Strings for Java, Java Script, HTML, XML, and SQL.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
iTake
  • 4,082
  • 3
  • 33
  • 26
  • I use org.apache.commons.lang3.StringEscapeUtils.escapeEcmaScript(text) to construct methodExpression in Java. Thanks. – Harun May 17 '17 at 04:23
1

I have done a sample one using jQuery

var descr = 'test"inside"outside';
$(function(){
   $("#div1").append('<a href="#" onclick="DoEdit(descr);">Click Me</a>');       
});

function DoEdit(desc)
{
    alert ( desc );
}

And this works in Internet Explorer and Firefox.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rahul
  • 184,426
  • 49
  • 232
  • 263
  • 5
    Of course it does, because you aren't putting it directly in the attribute. To use your method, I'd have to create an array of JS strings, then do an arbitrary number of $("#divxxx")... assignments. Less than optimal, but thanks for the suggestion. – Matt Dawdy Jan 05 '10 at 05:14
1

You can copy those two functions (listed below), and use them to escape/unescape all quotes and special characters. You don't have to use jQuery or any other library for this.

function escape(s) {
    return ('' + s)
        .replace(/\\/g, '\\\\')
        .replace(/\t/g, '\\t')
        .replace(/\n/g, '\\n')
        .replace(/\u00A0/g, '\\u00A0')
        .replace(/&/g, '\\x26')
        .replace(/'/g, '\\x27')
        .replace(/"/g, '\\x22')
        .replace(/</g, '\\x3C')
        .replace(/>/g, '\\x3E');
}

function unescape(s) {
    s = ('' + s)
       .replace(/\\x3E/g, '>')
       .replace(/\\x3C/g, '<')
       .replace(/\\x22/g, '"')
       .replace(/\\x27/g, "'")
       .replace(/\\x26/g, '&')
       .replace(/\\u00A0/g, '\u00A0')
       .replace(/\\n/g, '\n')
       .replace(/\\t/g, '\t');

    return s.replace(/\\\\/g, '\\');
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
omanosoft
  • 4,239
  • 1
  • 9
  • 16
0

Escape whitespace as well. It sounds to me like Firefox is assuming three arguments instead of one. &nbsp; is the non-breaking space character. Even if it's not the whole problem, it may still be a good idea.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
the Hampster
  • 876
  • 1
  • 14
  • 21
0

You need to escape quotes with double backslashes.

This fails (produced by PHP's json_encode):

<script>
  var jsonString = '[{"key":"my \"value\" "}]';
  var parsedJson = JSON.parse(jsonString);
</script>

This works:

<script>
  var jsonString = '[{"key":"my \\"value\\" "}]';
  var parsedJson = JSON.parse(jsonString);
</script>
Buffalo
  • 3,861
  • 8
  • 44
  • 69
-2

You can use the escape() and unescape() jQuery methods. Like below,

Use escape(str); to escape the string and recover again using unescape(str_esc);.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abhiram
  • 1,459
  • 14
  • 23
  • 1
    Use of the `escape()` function is discouraged. Use `encodeURI()` or `encodeURIComponent()` instead. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape – dearsina Aug 25 '22 at 12:13