4

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=?

17
  • 4
    // is not an html comment...they look like <!-- --> Commented Nov 14, 2016 at 7:40
  • And closing tag is also wrong Commented Nov 14, 2016 at 7:42
  • 1
    @BharatPatidar I know it's wrong. But, for this malformed HTML code, why this difference between .innerHTML() and Jquery's .html()? Commented Nov 14, 2016 at 7:44
  • 3
    Difference between innerHTML and .html() from jQuery Commented Nov 14, 2016 at 7:46
  • @prasad That doesn't answer the second part. Why b and c doesn't execute with .html()? Commented Nov 14, 2016 at 7:51

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

8 Comments

Although interesting, this is also stated in the documentation quite clearly: By design, any jQuery constructor or method that accepts an HTML string — jQuery(), .append(), .after(), etc. — can potentially execute code. This can occur by injection of script tags or use of HTML attributes that execute code (for example, <img onload="">)
it answers why it executes the a, but still hasn't answer the OP's real question, why $("body").html("<iframe><iframe><script>alert(1)</script>"); doesn't execute the alert?
@elfan, i get next error for this code Uncaught SyntaxError: Invalid or unexpected token
@Grundy, me too, I don't know why, but when I retyped it, it doesn't have syntax error anymore
I cannot edit my comment the second time. The OP's real question is, why $("body").html("<iframe><iframe>//<script>alert(1)</script>"); doesn't execute the script?
|
2

I think here what's happened

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

is not executed because //<script>alert(1)</script> is considered as the contents of <iframe> tag (that is not closed yet). As we know, the contents of the iframe gets ignored (it is only processed by browsers that don't support iframe).

While

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

is executed because <iframe//> is considered as <iframe /> which may be interpreted as finished/closed tag just like <br /> (at least in Chrome, FF, Edge, and IE). Now that the iframe element is finished/completed, the next element (<script>alert(1)</alert>) gets processed.

1 Comment

I am more sure of my answer, after seeing the inner working of jquery code as shown in the asnwer by @Grundy, see my comment below it.
-1

Let's see first what gets executed, apart from what you mentioned

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

Then what doesn't gets executed

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

In the second example from what works you can see it's not the // which is causing the issue. So it can be clearly observed in cases which iframe tag is left opened the script doesn't execute.

As I mentioned in the comments before ( I forgot to include it here ), if iframe tag is closed then the script gets executed as it is in the reference of the current page.

Update:

If you run this

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

and check the innerHTML of the iframe, it shows

&lt;div&gt;Hi&lt;/div&gt; '&lt;script&gt;alert(1)&lt;/script&gt;'

which explains why the script is not getting executed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.