unix_root unix_root - 25 days ago 7
HTML Question

HTML.innerHTML vs Jquery.html() - Javascript execution

Ref: html() vs innerHTML jquery/javascript & XSS attacks

From this, I can infer that, Jquery extracts the

<script>
tags and execute separately in DOM, it doesn't appear in DOM.

Consider the following HTML code:

a =
<iframe><iframe //><script>alert(1)</script>


b =
<iframe><iframe> //<script>alert(1)</script>


As of the code in
a
,
body.innerHTML = a;
doesn't execute the script, but
$("body").html(a);
does.

Why? Jquery's
.html()
execute the content after
//
but
.innerHTML =
doesn't?

If it is so, why
b
inside either
.innerHTML =
or
.html()
doesn't get executed?

Update: For a demo, open up console, and execute this:


  1. document.body.innerHTML = "<iframe><iframe //><script>alert(1)</script>"

  2. $("body").html("<iframe><iframe //><script>alert(1)</script>");



1 will not execute alert(), but 2 will. Replace the HTML values with
b
. Neither will get executed.

Update 2: From what I can determine that the HTML code will get executed in Jquery's
body()
but not in
.innerHTML=
?

Answer

If go a bit deeper in jQuery source code, we can find html method.

In this method exist next line

this.empty().append( value );

If now go to append, we can find next

append: function() {
    return domManip( this, arguments, function( elem ) {
        if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
            var target = manipulationTarget( this, elem );
            target.appendChild( elem );
        }
    } );
}

So, now find domManip. Inside this function from html-string builded fragmen, and if fragment have script tag execute next code

DOMEval( node.textContent.replace( rcleanScript, "" ), doc );

Where DOMEval

function DOMEval( code, doc ) {
    doc = doc || document;

    var script = doc.createElement( "script" );

    script.text = code;
    doc.head.appendChild( script ).parentNode.removeChild( script );
}

So, at least, we find place where execute scripts.


So, why in some case html run script and otherwise not?

This depends on input string and what return buildFragment function.

Inside buildFragment we can found next line

tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

where elem is input string, and jQuery.htmlPrefilter is next function

htmlPrefilter: function( html ) {
    return html.replace( rxhtmlTag, "<$1></$2>" );
}

so, input string just replaced with some regular exporession rxhtmlTag.

rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,

So, just try this for checking string:

console.log(jQuery.htmlPrefilter("<iframe><iframe //><script>alert(1)</" + "script>"));
console.log(jQuery.htmlPrefilter("<iframe><iframe> // <script>alert(1)</" + "script>"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>

So, in first case as result was

<iframe><iframe /></iframe><script>alert(1)</script>

And after insert it as innerHTML in tmp div, inside div create two elements: iframe and script. So after this script available for finding and executing

In second case:

<iframe><iframe> // <script>alert(1)</script>

String not changed, and after insert it as innerHTML in tmp div, inside div create just one iframe element with encoded content. That's why in this case script not execute.