ユーザーからの入力に基づき, 自由にHTMLを生成する
テキスト装飾用のHTMLを埋め込むためのリッチテキストエディタや,
通常,
<script src="lib/marked.js"></script>
...
<div id="content"></div>
<script>
var markdownText = "# title\n\n-list 1\n-list 2\n";
document.getElementById("content").innerHTML = marked(markdownText);
</script>
このとき,
じつは,
// 自由なHTMLの生成を抑制
var markdownText = "# title\n\n<img src=# onerror=alert(1)>\n<img src='/img/fig.png'>";
document.getElementById("content").innerHTML = marked(markdownText,{sanitize:true}); // <img>はどちらも生成されない
ただし,
そこで,
このような場合に採れる方法として,
DOMParser APIやcreateHTMLDocument APIは,
DOMParserを使ってDOMツリーを構築し,
function safeHtml (htmlString) {
var parser, doc, body, i, newNode, parentNode, buildNode;
parser = new DOMParser();
doc = parser.parseFromString(htmlString, "text/html");
body = doc.body;
parentNode = document.createElement("div");
buildNode = function (node) {
var i, elm, childNode, attrName, attrValue;
switch (node.nodeType) {
case 1: // ELEMENT_NODE
if (node.tagName === "DIV" || node.tagName === "IMG") {
elm = document.createElement(node.tagName);
if (node.tagName === "IMG") {
for (i=0; i<node.attributes.length; i++) {
attrName = node.attributes[i].name;
attrValue = node.attributes[i].value;
if (attrName === "src" || attrName === "title" || attrName === "alt") {
elm.setAttribute( attrName, attrValue );
}
}
}
for (i=0; i<node.childNodes.length; i++) {
console.log(node.childNodes[i]);
childNode = buildNode(node.childNodes[i]);
if (childNode !== undefined) {
elm.appendChild( childNode );
}
}
}
break;
case 3: // TEXT_NODE
elm = document.createTextNode(node.textContent);
break;
}
return elm;
};
for (i=0; i <body.childNodes.length; i++) {
newNode = buildNode(body.childNodes[i]);
if (newNode !== undefined) {
parentNode.appendChild(newNode);
}
}
return parentNode.innerHTML;
}
unsafeHtml = '<div>Hello, Sanitize!<img src=# alt="incorrect image" onerror=alert(1)></div>';
sanitizedHtml = safeHtml(unsafeHtml);
elm.innerHTML = sanitizedHtml; // <div>Hello, Sanitize!<img src="#" alt="incorrect image"></div>
この例では,
たとえば,
<div>Hello, Sanitize!<img src=# alt="incorrect image" onerror=alert(1)></div>
結果として,
<div>Hello, Sanitize!<img src="#" alt="incorrect image"></div>
実際にこのような方法で安全なHTMLを組み立てるためのライブラリの実装としては,