7

So as a rule of thumb I once learned that adding or removing HTML with JavaScript/JQuery (.html(),.append(), etc) leaves yourself wide open for DOM Based XSS Attacks. It is now my understanding that this is not 100% true. Supposedly there is a correct and safe way to add/remove HTML with JavaScript. I am hoping to learn some on what this "correct way" may be.

So as an example lets say I have an input filed that allows a user to append an item to a list. In this case the input would also be added to an array to be sent in future requests. Additionally this list would have a button to remove said item from that list. In an insecure environment we might do something like the following (negating array):

var list = $("#my_list");

$("#add_btn").on("click", function(){
    let input = $("#input_field").val();
    list.append(
        '<li>'+input+' <button>Remove</button></li>'
    );
});


$("#my_list").on("click", "button", function(){
    $(this).closest("li").remove();
});

How might one do the same but without the threat of XSS?

Link to JSFiddle demonstrating different suggested solutions

6
  • 1
    Hey, just to let you know, it's not recommended to cross post on multiple Stack Exchange sites. See this FAQ for more May 18, 2020 at 17:10
  • @FireQuacker I will remember this going forward, thank you. May 18, 2020 at 17:13
  • has nothing to do with javascript per say, but I would research something like anti-forgery tokens, which makes some cross site attacks more difficult to perform... docs.microsoft.com/en-us/aspnet/web-api/overview/security/…
    – pcalkins
    May 18, 2020 at 22:08
  • @pcalkins I believe you may be confusing XSS for CSRF May 19, 2020 at 16:39
  • yes, not all that familiar with terminology... but I believe there are XSS attacks that perform CSRF attacks.... (if a user visits a phishing site or has some malware plugin installed... that kind of thing... )
    – pcalkins
    May 19, 2020 at 17:23

1 Answer 1

5

Creating the DOM as string and using append or html indeed leads to DOM-based XSS. What you should do instead is to built the DOM elements using the proper functions and only inserting user-supplied input as text. Example:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<ul id=my_list class=my_list></ul>
<input type=text id=input_field value="<img src=x onerror=alert(1)>">
<button id=add_btn></button>

<script>
var list = $("#my_list");
$("#add_btn").on("click", function(){
    let input = $("#input_field").val();

    // this is insecure:
    //list.append('<li>'+input+' <button>Remove</button></li>');

    // this is secure:
    var listentry = document.createElement('li');
    listentry.innerText = input;
    list.append(listentry);
});
</script>
12
  • Would manipulating the DOM by removing elements open any attack vectors that could be mitigated in a similar manner? Something like $(this).closest("li").remove(); May 19, 2020 at 14:45
  • 1
    @FamousAv8er Not as far as I know (and it really shouldn't happen, as you are not building DOM elements with user input, but just calling functions on some DOM element which we don't know anything about; if that would for some reason trigger an XSS payload, I'd consider it a vulnerability in jQuery).
    – tim
    May 19, 2020 at 15:41
  • 1
    @dandavis It doesn't. text transforms the input to a string (which it already is). But when you then insert it along with the other string (<li><button>Remove</button></li>) into the DOM via append, it will be converted to DOM elements, thus triggering any JavaScript it may contain.
    – tim
    May 19, 2020 at 18:31
  • 1
    @tim I have updated the JSFiddle to reflect this addition jsfiddle.net/zjr907h8 May 20, 2020 at 16:39
  • 1
    @FamousAv8er The button doesn't seem to contain variables, so it should be fine as-is. But you should still be able to create it via document.createElement. To add attributes, you can use listentry.setAttribute('data-value', [value]);, which is secure (as in, the value input is treated as text).
    – tim
    Jun 16, 2020 at 15:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .