如何安全地在浏览器中运行用户提供的Javascript代码?

时间:2014-03-19 12:35:51

标签: javascript security virtual-machine xss

想象一下我想要不断调用用户提供的Javascript代码的场景,如下例所示,其中getUserResult是某个用户(非我自己)编写的函数:

for (var i = 0; i < N; ++i) {
    var x = getUserResult(currentState);
    updateState(currentState, x);
}

如何在浏览器和/或Node.js中执行这类代码,而不存在任何安全风险?

更一般地说,如何执行不允许修改甚至读取当前网页或任何其他全局状态的Javascript函数?有没有类似于浏览器内的&#34; JS虚拟机&#34;?

JSFiddle如何确保您无法运行任何恶意代码(至少它可能会破坏您的登录名,在页面的生命周期内运行机器人,如果没有做更糟糕的事情)?或者根本不确定它?

3 个答案:

答案 0 :(得分:7)

经过深思熟虑并在这个帖子中的其他海报的帮助下(非常感谢你的帮助!),我找到了第一批问题的答案。我在这里重写我的答案,因为它总结了概念,并为您提供了一些实际的代码来进行实验。

通常,这个问题有两种解决方案:我们可以使用iframeWorker在隔离环境中运行代码,从而无法读取或写入当前页面的信息(是我的第一个主要安全问题)。此外,还有沙盒方法,例如Google Caja,但(默认情况下)也会在iframe中运行其代码。

正如Juan Garcia所提议的那样,我将使用Web worker API,但这不是完整的故事。即使工作者无法直接从托管页面访问任何内容,仍然存在相当多的安全风险。 This site lists all built-ins available in a Worker's context

This JSFiddle演示了一种在window上下文之外运行一串代码的方法,而不必通过服务器,这仍然是不安全的,正如评论中所指出的那样。

我对此进行了扩展,采用了基于黑名单的方法,通过取消以下所有内容来禁用所有外部通信:

  • Worker
  • WebSocket
  • XMLHttpRequest
  • importScripts

但是,正如here所解释的那样,我目前正致力于将其移植到白名单方法中,以使其(近)未来安全。

如需了解更多信息,请考虑:

答案 1 :(得分:6)

你可以和工人一起做。关于worker的最好的事情是它们在不同的进程中运行,因此如果该用户代码进入无限循环,则不会挂起您的页面。与worker的唯一接口是消息接口,因此只交换字符串,这是非常安全的,但在某些情况下是有限的。

由于并非所有当前使用的浏览器都支持工作人员,因此iframe是一种有用的选择。您可以在javascript中创建它们,将display设置为'none',将它们添加到文档中,从iframe contentWindow获取eval函数,然后'destroy'iframe,就像将outerHTML设置为''(空字符串)一样。这很棘手,因为有时候iframe窗口会收集垃圾,但如果你设法做得对,你就会得到一个eval,它绑定了一个不同的全局对象,它有一个空文档。然后,您可以使用运行它的代码创建一个接口,该代码全局,页面中的代码全局运行。安全性取决于您如何实现该接口。您不应公开全局对象,这意味着在运行任何用户代码之前,您应该取消iframe全局中的“父”属性。您还应该确保没有将任何Element对象从页面文档传递到iframe全局中运行的代码,或者运行该代码的用户将能够通过parentElement属性导航整个文档,您应该将它们包装到例如,使用Object.defineProperty的Element接口。它做了很多工作,它只做了一次,但不确定浏览器之间是否兼容。例如,如果我记得并且我没有犯错,Chrome让我取消iframe全局中的父属性,而在iPad上的Safari我无法做到。抱歉,我现在没有任何代码可以与您分享,如果我有时间,我会发布。但是,iframes脚本在与页面相同的进程中运行,这意味着无限循环将挂起您的页面脚本,今天浏览器将代码编译为机器指令可以有效地挂起客户端操作系统(取决于浏览器和OS)。

第三,你可以使用沙盒,在T.J.中有JavaScript自我解释器。 Crowder评论编译器会为你简化,但副作用是它会运行得更慢,特别是解释器。

恕我直言,我认为ECMA的人们应该更少担心丑陋的箭头语法和类似的东西,并实现一种运行流程的安全方式,具有不同的全局,具有特定文档元素及其后代的接口但无法获得元素父级和对文档的访问权限。这将有效地实现编写JavaScript插件的方式,并且还可以保护广告系统。

答案 2 :(得分:1)