保护JavaScript eval功能

hei*_*nob 11 javascript eval

我们希望让用户能够在我们的应用程序中执行自己创建的JavaScript代码.为此,我们需要eval用来评估代码.为了将所有安全问题降至最低(如果不是零),我们的想法是防止在代码中使用任何windowdocument函数.所以没有XMLHttpRequest或类似的东西.

这是代码:

function secure_eval(s) {
    var ret;

    (function(){
        var copyXMLHttpRequest = XMLHttpRequest; // save orginal function in copy

        XMLHttpRequest = undefined; // make orignal function unavailable

        (function() {
            var copyXMLHttpRequest; // prevent access to copy

            try {
                ret = eval(s)
            } catch(e) {
                console.log("syntax error or illegal function used");
            }

        }())
        XMLHttpRequest = copyXMLHttpRequest; // restore original function
    }())
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

其工作原理如下:

secure_eval('new XMLHttpRequest()'); // ==> "illegal function used"
Run Code Online (Sandbox Code Playgroud)

现在我有几个问题:

  1. 这种模式是正确的安全方式eval吗?
  2. 什么功能windowdocument是被认为有害的人?
  3. 运送问题2.我试图掩盖所有(本机)函数window但我无法枚举它们:

例如,这不列出XMLHttpRequest:

for( var x in window) {
    if( window[x] instanceof Function) {
        console.log(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法让所有的原生功能的列表windowdocument

编辑:

我的一个想法是执行evala Worker并阻止访问 XMLHttpRequestdocument.createElement(参见上面的解决方案).这会(在我看来)产生以下后果:

  • 无法访问原始版本 document
  • 无法访问原始版本 window
  • 没有机会与外部资源进行通信(没有ajax,没有脚本)

你看到这里有任何缺点或泄漏吗?

EDIT2:

与此同时,我发现这个问题的答案解决了我的许多问题以及一些我甚至没有想过的事情(即浏览器死锁"while(true){}".

Lou*_*uis 16

您的代码实际上并没有阻止使用XMLHttpRequest.我可以XMLHttpRequest用这些方法实例化一个对象:

secure_eval("secure_eval = eval"); // Yep, this completely overwrites secure_eval.
secure_eval("XMLHttpRequest()");
Run Code Online (Sandbox Code Playgroud)

要么:

secure_eval("new (window.open().XMLHttpRequest)()")
Run Code Online (Sandbox Code Playgroud)

要么:

secure_eval("new (document.getElementById('frame').contentWindow.XMLHttpRequest)()")
Run Code Online (Sandbox Code Playgroud)

第三种方法依赖于iframe页面HTML中的a 的存在,有人可以通过在浏览器中操作DOM来添加.我不时地用Greasemonkey做这样的操作来消除烦恼或修复破坏的GUI.

这花了我大约5分钟才弄清楚,我绝不是一个安全大师.而这些只是我能够迅速找到的漏洞,可能还有其他漏洞,我不知道.这里的教训是,确保代码安全真的非常难eval.

使用工人

好的,所以使用a Worker运行代码将处理上面的第2和第3个案例,因为没有窗口可访问Worker.并且......嗯..第一种情况可以通过secure_eval其范围内的阴影来处理.故事结局?要是...

如果我放入secure_eval一个Web worker并运行以下代码,我可以重新获取XMLHttpRequest:

secure_eval("var old_log = console.log; console.log = function () { foo = XMLHttpRequest; old_log.apply(this, arguments); };");
console.log("blah");
console.log(secure_eval("foo"));
Run Code Online (Sandbox Code Playgroud)

其原理是可用于覆盖功能使用外secure_eval捕捉到XMLHttpRequest由它分配给将要故意泄露给工人的全球空间的变量,等到功能外使用由工人secure_eval,然后抢保存的值.console.log上面的第一个模拟了外部篡改功能的使用,secure_eval第二个console.log显示了捕获的值.我用过console.log,为什么不呢?但实际上全局空间中的任何函数都可以像这样修改.

实际上,为什么要等到工人可以使用我们篡改的某些功能?这是另一种更好,更快捷的访问方式XMLHttpRequest:

secure_eval("setTimeout(function () { console.log(XMLHttpRequest);}, 0);");
Run Code Online (Sandbox Code Playgroud)

即使在一个工人(有一个原始的console.log),这将输出XMLHttpRequest到控制台的实际值.我还要注意,this传递给函数的内部值setTimeout是全局范围对象(即window不在worker或selfworker中),不受任何变量阴影的影响.

本问题中提到的其他问题怎么样?

这里的解决方案怎么样?好多了,但在Chrome 38中运行时还有一个漏洞:

makeWorkerExecuteSomeCode('event.target.XMLHttpRequest', 
    function (answer) { console.log( answer ); });
Run Code Online (Sandbox Code Playgroud)

这将显示:

function XMLHttpRequest() { [native code] }
Run Code Online (Sandbox Code Playgroud)

再说一遍,我不是一个安全大师,也不是故意制造麻烦的人.可能还有更多我没想过的方法.


Sci*_*ter 2

我将在这里尝试按顺序回答您的问题。

这种模式是确保安全的正确方法eval吗?

这部分有点主观。我认为这没有任何重大的安全缺陷。我尝试了多种方法来访问XMLHttpRequest,但无法:

secure_eval('XMLHttpRequest')
secure_eval('window.XMLHttpRequest')
secure_eval('eval("XMLHttpRequest")()')
secure_eval('window.__proto__.XMLHttpRequest') // nope, it's not inherited
Run Code Online (Sandbox Code Playgroud)

但是,如果你想把更多的东西列入黑名单,那就会很多了。

哪些功能被认为是有害的windowdocument

这取决于您认为什么“有害”。如果 DOM 完全可以访问是不是很糟糕?或者 WebKit 桌面通知或语音合成怎么样?

您必须根据您的具体用例来决定。

为了解决问题 2。我尝试屏蔽 的所有(本机)函数window,但我无法枚举它们:

这是因为大多数方法都是不可枚举的。要枚举,您可以使用Object.getOwnPropertyNames(window)

var globals = Object.getOwnPropertyNames(window);
for (var i = 0; i < globals.length; i++) {
    if( window[globals[i]] instanceof Function) {
        console.log(globals[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

eval我的想法之一是在 a 内执行Worker并阻止访问 XMLHttpRequestand document.createElement(请参阅上面的解决方案)。

这听起来是个好主意。