如何对不受信任的用户提交的 JavaScript 内容进行沙箱处理?
Posted
技术标签:
【中文标题】如何对不受信任的用户提交的 JavaScript 内容进行沙箱处理?【英文标题】:How can I sandbox untrusted user-submitted JavaScript content? 【发布时间】:2012-08-25 22:27:39 【问题描述】:我需要在我的网站上提供用户提交的脚本(有点像jsfiddle)。我希望脚本以安全的方式在访问者浏览器上运行,与提供它们的页面隔离。由于代码是用户提交的,不保证可信。
现在我能想到三个选项:
在不同域的 iframe 中提供用户提交的内容,并依赖同源策略。这将需要设置一个额外的域,如果可能的话,我想避免。我相信这就是 jsfiddle 的做法。该脚本仍然会造成一些损害,例如更改top.location.href
,这不太理想。 http://jsfiddle.net/PzkUw/
使用sandbox attribute。我怀疑这在浏览器中没有得到很好的支持。
在提供脚本之前对其进行清理。我宁愿不去那里。
上面还有其他解决方案或建议吗?
更新
如果我怀疑第一个选项是最佳解决方案,除了更改顶部窗口位置之外,恶意脚本还能做什么,我该如何防止这种情况发生?我可以操纵或拒绝某些脚本基于静态代码分析,但这是hard,考虑到可以访问对象的方式数量以及一般静态分析javascript的难度。至少,它需要一个成熟的解析器和一些复杂的规则(其中一些,但我怀疑不是全部,其中一些存在于 JSLint 中)。
【问题讨论】:
我认为你的子域想法是最好的。我自己研究了这个问题,找不到更好的解决方案。我曾经玩过通过 XmlHttpRequest 动态加载脚本并运行 eval ——不过我不记得我为什么放弃它了。 相关:***.com/questions/958997/… 我同意@JeremyJStarcher。无论如何,你是否有机会控制某些 JS 元素,window 是最重要的?如果是这样,我会尝试让它拒绝从 iframe 发出的某些请求,但我不确定这有多容易。 As of now (more than 2 years after you asked your question) browser support for sandbox is pretty good. iframe + 沙盒似乎是推荐的解决方案:medium.com/zendesk-engineering/… 【参考方案1】:创建一个定义良好的消息接口,并将 JavaScript Web Worker 用于您想要沙箱的代码。 html5 Web Workers
Web Workers 无权访问以下 DOM 对象。
窗口对象
文档对象
父对象
因此他们无法重定向您的页面或更改其中的数据。
您可以创建一个模板和一个定义良好的消息传递界面,以便用户可以创建 Web Worker 脚本,但您的脚本将对被操纵的内容拥有最终决定权。
EDIT Jordan Gray 的评论插入了一个似乎可以完成我上面描述的 JavaScript 库。 https://github.com/eligrey/jsandbox
【讨论】:
听起来是个不错的选择,但可能过于严格。尽管如此 +1 的想法。 好建议。我担心的是旧版浏览器不支持这一点。另外,网络工作者不能发出 AJAX 请求(这意味着我仍然需要从不同的域提供服务)? @Andrew - 您认为具有 AJAX 功能的网络工作者在什么情况下会成为问题?如果您担心工作脚本会在您自己的域中模拟用户,您可以使用无 cookie 会话并避免该问题。至于浏览器兼容性,是的,IE9及以下不支持HTML5。 @LastCoder 没错,浏览器会(我假设)使用任何 XHR 发送身份验证 cookie,然后攻击者可以访问私人信息。我宁愿从不同的域提供服务,而不是使用无 cookie 会话,因为它们容易泄漏(引荐标头、粘贴链接等) - 你能想到这不起作用的任何原因吗? 顺便说一下,您可能想添加一个指向jsandbox 的链接,这是一个使用这种方法的沙盒库。【参考方案2】:一些可能对您的应用程序有帮助的工具的想法 - 它们从两个不同的方向解决问题:Caja 将不受信任的 JavaScript 代码编译成安全的东西,而 AdSafe 定义了可以安全使用的 JavaScript 子集。
卡哈
Caja
Caja 编译器是一种工具,可让第三方 HTML、CSS 和 JavaScript 安全地嵌入您的网站。它支持嵌入页面和嵌入应用程序之间的丰富交互。 Caja 使用对象能力安全模型来支持广泛的灵活安全策略,以便您的网站可以有效地控制嵌入式第三方代码可以对用户数据执行的操作。
广告安全
AdSafe
ADsafe 可以安全地将访客代码(例如第三方脚本广告或小部件)放在网页上。 ADsafe 定义了一个足够强大的 JavaScript 子集,允许访客代码执行有价值的交互,同时防止恶意或意外损坏或入侵。 ADsafe 子集可以通过 JSLint 等工具进行机械验证,因此无需人工检查即可检查访客代码的安全性。 ADsafe 子集还强制执行良好的编码实践,增加来宾代码正确运行的可能性。
【讨论】:
我研究了 AdSafe。它是为不在框架中的脚本设计的,因此非常严格。例如,您不能使用a[i] = 1
。我认为这些限制可能会吓到大多数合法用户。将看看 Caja。
你可以做a[+i] = 1
。 (这是因为当有人写 a=window; i='ev'+'al'
时,a[i]
将意味着 eval
并且不可能静态消除这种可能性。)但你是对的,它可能对你的需求过于严格。【参考方案3】:
如前所述,iframe
的 sandbox
属性已被主流浏览器支持,但我另外建议一个混合解决方案:在沙盒 iframe 中启动 web-worker。这将提供一个单独的线程,并保护沙盒 iframe 的 DOM 免受不受信任的代码的影响。这就是我的Jailed 库的工作方式。此外,您可以通过将任何一组函数导出到沙箱来解决任何限制。
【讨论】:
关于您的库的问题,您为什么要在沙盒 iframe 和网络工作者中运行代码?拥有一个普通的 iframe,然后在 Web Worker 中运行不受信任的代码不是足够安全吗?除了您在 onmessage 回调中所做的事情之外,网络工作者无法访问 iframe 的 dom,或者让它真正做任何其他事情。我说的对吗? 嗯,不完全是。最初它只在 web worker 中运行代码,然后我被解释说这还不够,因为 worker 仍然可以访问一些本地源实例,比如本地存储、indexeddb 等。所以我不得不把一个 worker 放在一个沙盒 iframe。工作人员仍然有助于获取线程并防止以无限循环锁定页面。但后来似乎很多浏览器禁止在 https 下的 iframe 中运行 worker,所以现在库只在可能的情况下启动 worker,否则代码只是在 iframe 中运行。【参考方案4】:如果您想通过删除对
(function(window, document, parent /* Whatever you want to remove */)
console.log(this); // Empty object
console.log(window); // undefined
console.log(document); // undefined
console.log(parent); // undefined
).call();
用空对象调用它很重要,否则 this 将指向 window 对象
【讨论】:
console.log(function()return this;());
:P以上是关于如何对不受信任的用户提交的 JavaScript 内容进行沙箱处理?的主要内容,如果未能解决你的问题,请参考以下文章
Xcode 说:“身份 ___ 不受信任。”并且不允许我提交我的应用程序