![](/img/trans.png)
[英]How to lazy load HTML block (to avoid big DOM size), but also have web crawlers notice the lazy content?
[英]How to avoid XSS when trying to modify HTML content via DOM?
在大多数情况下,当我们想要操作字符串内容时,我们可能更愿意将其挂载到 DOM 树上并进行操作,而不是使用复杂的正则表达式替换,例如:
但是,当外部内容包含一些意外脚本时,这种方法总是会导致 XSS 问题,例如以下代码段:
const unsafe = '<img src=x onerror=alert(1)>';
$('<div>').html(unsafe).find('img').remove(); // leads to a XSS
const div = document.createElement('div');
div.innerHTML = unsafe; // leads to XSS
const img = div.querySelector('img');
img && img.parentNode.removeChild(img);
那么我们该如何解决这个问题呢?
回滚到复杂的正则表达式? 为了避免这个问题,大多数开发人员可能会使用一些库,如js-xss或DOMPurify来为他们处理复杂的正则表达式。 然而,这些库有时过于严格,无法删除一些安全标签,除非您可以设置正确的配置。
在这里,我只想澄清另一种简单的方法,我们可以依靠 iframe 沙盒技术,它还可以禁止浏览器访问来自加载图像等内容的资源:
const unsafe = '<img src=x onerror=alert(1)>';
const $frame = $('<iframe>').appendTo('body'), $sandboxDoc = $frame.contents();
$frame.remove();
// scripts have been blocked
// the document won't also access the image which throws us a 404
$('<div>', $sandboxDoc).html(unsafe).find('img').remove();
// by pure javascript
const frame = document.createElement('iframe');
document.body.appendChild(frame);
const sandboxDoc = frame.contentDocument;
frame.parentNode.removeChild(frame);
const div = sandboxDoc.createElement('div');
div.innerHTML = unsafe;
const img = div.querySelector('img');
img && img.parentNode.removeChild(img);
这样的文档仍然有一个副作用,即 DOM 节点不会计算出任何 styles:
$('<img style="cursor: zoom-in">', $sandboxDoc).css('cursor'); // => ''
// by pure javascript
const img = sandboxDoc.createElement('img');
img.setAttribute('style', 'cursor:zoom-in');
img.style.cursor; // => ''
这意味着我们在某些情况下会出现一些意想不到的结果,例如我们无法移除 cursor:
$('<img style="cursor: zoom-in">', $sandboxDoc)
.css({cursor : ''}).prop('outerHTML'); // => '<img style="cursor: zoom-in">'
// by pure javascript
img.style.cursor = '';
img.outerHTML; // => '<img style="cursor:zoom-in">'
为了解决这个问题,我们应该确保在删除文档之前构建 DOM 节点:
function $sandbox(content) {
const $frame = $('<iframe>').appendTo('body');
const $elem = $(content, $frame.contents());
$frame.remove();
return $elem;
}
$sandbox('<img style="cursor: zoom-in">').css('cursor'); // => 'zoom-in'
// by pure javascript
function sandbox(fn) {
const frame = document.createElement('iframe');
document.body.appendChild(frame);
const elem = fn(frame.contentDocument);
frame.parentNode.removeChild(frame);
return elem;
}
sandbox(sandboxDoc => {
const img = sandboxDoc.createElement('img');
img.setAttribute('style', 'cursor:zoom-in');
return img;
}).style.cursor; // => 'zoom-in'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.