作为markdown的替代方案,我正在寻找一种在JavaScript中安全地解析HTML的可配置子集的方法。
例如,对于
的(不可信)输入<b onclick="alert('XSS');" data-myapp="asdf" style="color:red">Hello</b>
<h1><i style="color:expression(alert('XSS'));"> World</i></h1>
带参数
allowTags: b, i
allowAttrs: data-myapp
allowSafeStyle: color
我期待输出
<b data-myapp="asdf" style="color:red">Hello</b>
<i> World</i>
Markdown似乎无法表达更复杂的属性。 Caja似乎与我想要的非常接近,但需要服务器端渲染。那么,如何在JavaScript中呈现安全(根据上述参数allowTags
,allowAttrs
等)HTML的子集?
答案 0 :(得分:1)
我使用jQuery使我的答案更短,并且包含更少的样板代码,但它不相关。
我正在使用.innerHTML
,因为它不会在html中执行可能的脚本或css。
在这里演示http://jsfiddle.net/QCaGq/
function filterData(data, options ){
var root;
try {
root = document.implementation.createHTMLDocument().body;
}
catch(e) {
root = document.createElement("body");
}
root.innerHTML = data;
$(root).find("*").filter(function(){
return options.allowTags.indexOf(this.tagName.toLowerCase()) === -1;
}).each( function() {
$(this).children().detach().insertBefore( this );
$(this).remove();
});
function removeStyle( node, attr ) {
var style = node.style,
prop,
name,
len = style.length,
i, val = "";
for( i = 0; i < len; ++i ) {
name = style[i];
prop = style[name];
if( options.allowSafeStyle.indexOf( name ) > -1 ) {
val += (name + ":" + prop + ";");
}
}
if( val ) {
attr.nodeValue = val;
}
else {
node.removeAttribute("style");
}
}
function removeAttrs( node ) {
$.each( node.attributes, function( index, attr ) {
if( !attr ) {
return;
}
if( attr.name.toLowerCase() === "style" ) {
return removeStyle( node, attr );
}
if( options.allowAttrs.indexOf(attr.name.toLowerCase()) === -1 ) {
node.removeAttribute(attr.name);
}
});
}
function walk( root ) {
removeAttrs(root);
$( root.childNodes ).each( function() {
if( this.nodeType === 8 ) { //Remove html comments
$(this).remove();
}
else if( this.nodeType === 1 ) {
walk(this);
}
});
}
walk(root);
return root.innerHTML;
}
var opts = {
allowTags: ["b", "i"],
allowAttrs: ["data-myapp"],
allowSafeStyle: ["color"]
}
filterData( '<b onclick="alert(\'XSS\');" data-myapp="asdf" style="color:red">Hello</b>\n<h1><i style="color:expression(alert(\'XSS\'));"> World</i></h1>', opts );
结果:
<b data-myapp="asdf" style="color:red;">Hello</b>
<i> World</i>
这应该让你开始。