Search code examples
javascriptjqueryhtmlhtml-escape-characters

JQuery - Add regular HTML along with escaped HTML


I store some data in firebase (which can be retrieved in the client), and then, I add it to the HTML using JQuery. This is easy - I just prepend the data to the DOM element. However, the issue is, this raw code will be vulnerable to attacks, so I need to properly escape the data taken from the database before adding it to the HTML. I thought the following code would do the job:

function escapeHTML(text) {
  var map = {
    '&': '&',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}

$('#element').prepend('<h1>Heading</h1><p>' + escapeHTML(data) + '</p>');

When I test this code, by making the value of data something like <script>alert('This should not work');</script>, I thought that it would just add this text to the <p></p> tags, without executing the JS, but it actually ran the code.

I understand that using $('#element').text() will escape the text for me, but I don't want everything to get escaped - I still want to add the <h1></h1> and <p></p> tags, I just need the variable "data" to be escaped. I saw a couple of StackOverflow posts on similar topics, but none of them seem to address this issue - post 1, post 2, post 3.


Solution

  • The reason the code in your question didn't work is because all the entities like &amp; in the Javascript are parsed as the characters they represent when the JS in the HTML is parsed. It would work if you put the code in an external .js file, since that's not parsed as HTML. Or you could double-encode them:

      var map = {
        '&': '&amp;amp;',
        '<': '&amp;lt;',
        '>': '&amp;gt;',
        '"': '&amp;quot;',
        "'": '&amp;#039;'
      };
    

    But a better way is to create the <h1> and <p> elements separately, and put the escaped text in the paragraph using a jQuery method.

    const data = '<scr' + 'ipt>alert("foo");</scr' + 'ipt>';
    
    $("#element").prepend("<h1>Heading</h1>", $("<p>", {text: data}));
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="element"></div>

    If you want to fill in data attributes, you can do it similarly:

    $("#element").prepend($("<div>", {
        data: {
            attr: data,
            another: someMoreData
        },
        text: "hello world"
    }));