0

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.

cubetastic
  • 21
  • 1
  • 5

1 Answers1

0

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"
}));
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • doubt this would meet the OPs needs if the content contains tags like bold and such. Maybe it is plain text and would be fine.... – epascarello Jun 15 '18 at 17:49
  • Why do you say that? – Barmar Jun 15 '18 at 17:52
  • @Barmar I am actually adding the data from firebase like this: `$('#element').prepend('
    hello world
    ')`. So, I don't know how to use your JQuery method... Also, this is already in an external JS file, and even if it wasn't, I don't think it would get parsed as HTML - it's in a string. But this is probably not the cause of my issue. However, your double escaping method worked like a charm! Thanks a lot! I can't upvote you yet though, as my rep is too low
    – cubetastic Jun 16 '18 at 02:34
  • I've added code that shows how to fill in the data attributes using the object method. – Barmar Jun 16 '18 at 14:17