"new DOMParser.parseFromString" 能比 "createElement" 更安全吗?
Can a "new DOMParser.parseFromString" be safer than "createElement"?
我创建了一个脚本来尝试删除不安全的内容(我将其用于浏览器扩展):
var str = "<strong>Hello</strong> mundo <script src="http://site/badscript.js"></script>";
CreateDOM(str);
function RemoveAttrs(target)
{
var attrs = target.attributes, currentAttr;
var validAttrs = [ "href", "class", "id", "target" ];
for (var i = attrs.length - 1; i >= 0; i--) {
currentAttr = attrs[i].name;
if (attrs[i].specified && validAttrs.indexOf(currentAttr) === -1) {
target.removeAttribute(currentAttr);
}
if (
currentAttr === "href" &&
/^(#|javascript[:])/gi.test(target.getAttribute("href"))
) {
target.parentNode.removeChild(currentAttr);
}
}
}
function RemoveEls(target)
{
var current;
//Remove elements insecure (blacklist)
var list = target.querySelectorAll("script,link,...");
for (var i = list.length - 1; i >= 0; i--) {
current = list[i];
current.parentNode.removeChild(current);
}
//Remove insecure attributes (whitelist)
list = target.getElementsByTagName("*");
for (i = list.length - 1; i >= 0; i--) {
RemoveAttrs(list[i]);
}
return target;
}
function CreateDOM(MinhaString)
{
var tmpDom = document.createElement("div");
tmpDom.innerHTML = MinhaString;
tmpDom = RemoveEls(tmpDom);
//Inject in container
document.getElementById("container").appendChild(tmpDom);
}
我在为 Opera 和 Google Chorme 创建的插件中使用此脚本,但是网站版主 ("addons.opera.com") 对我说:
Your cleanDomString method is not safe, please replace:
tmpDom.innerHTML = data; with: var tmpDom = (new
DOMParser).parseFromString(data, "text/html").body;
and remove: var tmpDom = document.createElement("div");
or use:
https://github.com/operatester/safeResponse/blob/1.1/safeResponse.js
dmichnowicz; May 30, 2016 8:46:57 AM UTC
代码如下所示:
var str = "<strong>Hello</strong> mundo <script src="http://site/badscript.js"></script>";
CreateDOM(str);
function RemoveAttrs(target)
{
var attrs = target.attributes, currentAttr;
var validAttrs = [ "href", "class", "id", "target" ];
for (var i = attrs.length - 1; i >= 0; i--) {
currentAttr = attrs[i].name;
if (attrs[i].specified && validAttrs.indexOf(currentAttr) === -1) {
target.removeAttribute(currentAttr);
}
if (
currentAttr === "href" &&
/^(#|javascript[:])/gi.test(target.getAttribute("href"))
) {
target.parentNode.removeChild(currentAttr);
}
}
}
function RemoveEls(target)
{
var current;
//Remove elements insecure (blacklist)
var list = target.querySelectorAll("script,link,...");
for (var i = list.length - 1; i >= 0; i--) {
current = list[i];
current.parentNode.removeChild(current);
}
//Remove insecure attributes (whitelist)
list = target.getElementsByTagName("*");
for (i = list.length - 1; i >= 0; i--) {
RemoveAttrs(list[i]);
}
return target;
}
function CreateDOM(MyString)
{
var tmpDom = (new DOMParser).parseFromString(MyString, "text/html").body;
tmpDom = RemoveEls(tmpDom);
//Inject in container
document.getElementById("container").appendChild(tmpDom);
}
我进行了更改,但我想了解是什么让我的代码变得更安全。对我来说,他们似乎都在做同样的事情。
有什么区别(安全性方面)?
实际上,您当前的代码并不安全。 innerHTML
不会在创建的 <script>
元素中 运行 脚本,但会 运行 事件处理程序内容属性。
function createDOM(str) {
document.createElement("div").innerHTML = str;
}
createDOM('<img src="//" onerror="console.log(\'You are pwned!\')" />');
function createDOM(str) {
new DOMParser().parseFromString(str, "text/html");
}
createDOM('<img src="//" onerror="console.log(\'You are safe\')" />');
但是请注意,如果您只想操作不受信任的 HTML 字符串中的 DOM 元素,则 DOMParser
可以提供安全性。这就像一个沙盒。但是如果你得到这些元素并将其附加到当前文档中,它们仍然可以 运行 JS.
function createDOM(str) {
document.body.appendChild(new DOMParser().parseFromString(str, "text/html").body);
}
createDOM('<img src="//" onerror="console.log(\'You are pwned!\')" />');
如果你真的需要这样的东西,我会使用一个包含允许的元素和属性的小白名单,并去掉其他所有东西。
我创建了一个脚本来尝试删除不安全的内容(我将其用于浏览器扩展):
var str = "<strong>Hello</strong> mundo <script src="http://site/badscript.js"></script>";
CreateDOM(str);
function RemoveAttrs(target)
{
var attrs = target.attributes, currentAttr;
var validAttrs = [ "href", "class", "id", "target" ];
for (var i = attrs.length - 1; i >= 0; i--) {
currentAttr = attrs[i].name;
if (attrs[i].specified && validAttrs.indexOf(currentAttr) === -1) {
target.removeAttribute(currentAttr);
}
if (
currentAttr === "href" &&
/^(#|javascript[:])/gi.test(target.getAttribute("href"))
) {
target.parentNode.removeChild(currentAttr);
}
}
}
function RemoveEls(target)
{
var current;
//Remove elements insecure (blacklist)
var list = target.querySelectorAll("script,link,...");
for (var i = list.length - 1; i >= 0; i--) {
current = list[i];
current.parentNode.removeChild(current);
}
//Remove insecure attributes (whitelist)
list = target.getElementsByTagName("*");
for (i = list.length - 1; i >= 0; i--) {
RemoveAttrs(list[i]);
}
return target;
}
function CreateDOM(MinhaString)
{
var tmpDom = document.createElement("div");
tmpDom.innerHTML = MinhaString;
tmpDom = RemoveEls(tmpDom);
//Inject in container
document.getElementById("container").appendChild(tmpDom);
}
我在为 Opera 和 Google Chorme 创建的插件中使用此脚本,但是网站版主 ("addons.opera.com") 对我说:
Your cleanDomString method is not safe, please replace: tmpDom.innerHTML = data; with: var tmpDom = (new DOMParser).parseFromString(data, "text/html").body;
and remove: var tmpDom = document.createElement("div");
or use: https://github.com/operatester/safeResponse/blob/1.1/safeResponse.js
dmichnowicz; May 30, 2016 8:46:57 AM UTC
代码如下所示:
var str = "<strong>Hello</strong> mundo <script src="http://site/badscript.js"></script>";
CreateDOM(str);
function RemoveAttrs(target)
{
var attrs = target.attributes, currentAttr;
var validAttrs = [ "href", "class", "id", "target" ];
for (var i = attrs.length - 1; i >= 0; i--) {
currentAttr = attrs[i].name;
if (attrs[i].specified && validAttrs.indexOf(currentAttr) === -1) {
target.removeAttribute(currentAttr);
}
if (
currentAttr === "href" &&
/^(#|javascript[:])/gi.test(target.getAttribute("href"))
) {
target.parentNode.removeChild(currentAttr);
}
}
}
function RemoveEls(target)
{
var current;
//Remove elements insecure (blacklist)
var list = target.querySelectorAll("script,link,...");
for (var i = list.length - 1; i >= 0; i--) {
current = list[i];
current.parentNode.removeChild(current);
}
//Remove insecure attributes (whitelist)
list = target.getElementsByTagName("*");
for (i = list.length - 1; i >= 0; i--) {
RemoveAttrs(list[i]);
}
return target;
}
function CreateDOM(MyString)
{
var tmpDom = (new DOMParser).parseFromString(MyString, "text/html").body;
tmpDom = RemoveEls(tmpDom);
//Inject in container
document.getElementById("container").appendChild(tmpDom);
}
我进行了更改,但我想了解是什么让我的代码变得更安全。对我来说,他们似乎都在做同样的事情。
有什么区别(安全性方面)?
实际上,您当前的代码并不安全。 innerHTML
不会在创建的 <script>
元素中 运行 脚本,但会 运行 事件处理程序内容属性。
function createDOM(str) {
document.createElement("div").innerHTML = str;
}
createDOM('<img src="//" onerror="console.log(\'You are pwned!\')" />');
function createDOM(str) {
new DOMParser().parseFromString(str, "text/html");
}
createDOM('<img src="//" onerror="console.log(\'You are safe\')" />');
但是请注意,如果您只想操作不受信任的 HTML 字符串中的 DOM 元素,则 DOMParser
可以提供安全性。这就像一个沙盒。但是如果你得到这些元素并将其附加到当前文档中,它们仍然可以 运行 JS.
function createDOM(str) {
document.body.appendChild(new DOMParser().parseFromString(str, "text/html").body);
}
createDOM('<img src="//" onerror="console.log(\'You are pwned!\')" />');
如果你真的需要这样的东西,我会使用一个包含允许的元素和属性的小白名单,并去掉其他所有东西。