如果深入研究jQuery源代码,我们可以找到
html
方法。
在这个方法中存在下一个
行。
this.empty().append( value );
如果现在前往
append
,我们可以找到下一个。
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 );
}
} );
}
所以,现在找到
domManip
。在这个函数中,从HTML字符串构建出片段,如果片段中有脚本标记则执行
下一个代码。
DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
在哪里 DOMEval
function DOMEval( code, doc ) {
doc = doc || document;
var script = doc.createElement( "script" );
script.text = code;
doc.head.appendChild( script ).parentNode.removeChild( script );
}
所以,至少我们找到了执行脚本的地方。
所以,为什么有些情况下
html
可以运行脚本,而有些情况下却不行?
这取决于输入字符串以及返回值
buildFragment
函数。
在
buildFragment
中,我们可以找到
下一行。
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
其中,
elem
是输入字符串,
jQuery.htmlPrefilter
是下一个函数。
htmlPrefilter: function( html ) {
return html.replace( rxhtmlTag, "<$1></$2>" );
}
所以,输入字符串只是被一些
正则表达式rxhtmlTag
替换了。
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
所以,只需尝试使用以下方法检查字符串:
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>
所以,在第一种情况下,结果是:
<iframe><iframe /></iframe><script>alert(1)</script>
在第一个例子中,将其作为innerHTML插入到名为“tmp”的div中,在该div内创建两个元素:iframe和script。因此,在此之后,可以找到并执行此脚本。
在第二种情况下:
<iframe><iframe> // <script>alert(1)</script>
字符串未被更改,将其作为innerHTML插入到“tmp” div中,在div内仅创建一个带有编码内容的iframe元素。这就是为什么在这种情况下脚本不会执行的原因。