9

我真的很想为用户提供一些脚本功能,而不是让它访问更强大的功能,比如改变 DOM。也就是说,所有输入/输出都通过给定接口进行隧道传输。就像一种受限制的javacsript。

示例:如果接口是checkanswer(func) 允许的:

checkanswer( function (x,y)={
   return x+y;
}

但这些是不允许的:
alert(1)
document.write("hello world")
eval("alert()")

编辑:我想到的是一种使用 javascript 实现的简单语言,例如http://stevehanov.ca/blog/index.php?id=92

4

8 回答 8

13

编辑此答案与您的预编辑问题有关。不知道使用 Javascript 实现的任何脚本语言,尽管我希望有一些。例如,曾经有人为 Javascript 编写了 BASIC(曾经有一个链接,但是它腐烂了)。因此,这个答案的其余部分是相当学术的,但我把它留作讨论、说明甚至警告目的。另外,我绝对同意bobince 的观点 ——不要自己做,使用工作其他的,例如Caja。)

如果您允许在用户生成的内容中使用任何脚本,请做好准备,您将进入一场军备竞赛,人们会在您的保护机制中发现漏洞并利用它们,然后您对这些漏洞做出响应。我想我可能会回避它,但你知道你的社区和你处理虐待的选择。因此,如果您为此做好了准备:

由于 Javascript 进行符号解析的方式,似乎应该可以在window, document, ActiveXObject,XMLHttpRequest等不具有通常含义的上下文中评估脚本:

// Define the scoper
var Scoper = (function() {
    var rv = {};

    rv.scope = function(codeString) {
        var window,
            document,
            ActiveXObject,
            XMLHttpRequest,
            alert,
            setTimeout,
            setInterval,
            clearTimeout,
            clearInterval,
            Function,
            arguments;
            // etc., etc., etc.

        // Just declaring `arguments` doesn't work (which makes
        // sense, actually), but overwriting it does
        arguments = undefined;

        // Execute the code; still probably pretty unsafe!
        eval(codeString);
    };

    return rv;;
})();

// Usage:
Scoper.scope(codeString);

(现在使用 evil eval,但我不能立即想出一种方法来隐藏默认对象跨浏览器而不使用eval,并且如果您仍然以文本形式接收代码......)

但它不起作用,它只是一个部分解决方案(更多下文)。那里的逻辑是,代码中的任何codeString访问尝试window(例如)都将访问局部变量window,而不是全局变量;其他人也一样。不幸的是,由于符号的解析方式,window可以使用或不使用window.前缀 (alert例如) 访问 的任何属性,因此您也必须列出这些属性。这可能是一个很长的列表,尤其是因为正如bobince 所指出的,IE 会将任何带有名称或 ID 的 DOM 元素转储到window. 所以你可能不得不把所有这些都放在它自己的 iframe 中,这样你就可以围绕它进行最终运行问题和“仅”必须处理标准的东西。还要注意我是如何使scope函数成为对象的属性的,然后您只能通过属性调用它。这样this就设置为Scoper实例(否则,在原始函数调用中,this默认为window!)。

但是,正如 bobince 指出的那样,有很多不同的方法可以解决问题。例如,这段代码codeString成功地打破了上面的监狱:

(new ('hello'.constructor.constructor)('alert("hello from global");'))()

现在,也许您可​​以更新监狱以使该特定漏洞无法工作(对所有 -所有 - 内置对象的constructor属性进行处理),但我倾向于怀疑它。如果可以的话,有人(比如 Bob)会想出一个新的漏洞利用,比如这个:

(function(){return this;})().alert("hello again from global!");

于是就有了“军备竞赛”。

唯一真正彻底的方法是在您的站点中内置适当的 Javascript 解析器,解析其代码并检查非法访问,然后才让代码运行。这是很多工作,但如果你的用例证明它是合理的......

于 2010-04-20T08:54:32.547 回答
5

TJ Crowder 对“军备竞赛”提出了很好的观点。构建防水沙箱将非常困难。

但是,可以很容易地覆盖某些功能。

简单的功能:

根据这个问题,甚至覆盖之类的东西也document.write很简单

document.write = function(str) {}

如果这适用于您需要支持的浏览器(我假设它适用于所有浏览器),那可能是最好的解决方案。

备选方案:

  • 将脚本沙箱化到不同子域上的 IFrame 中。可以操作自己的 DOM 并发出 alert() 等,但周围的站点将保持不变。无论您选择哪种方法,您都可能必须这样做

  • 使用允许函数的白名单解析用户的代码。做起来也非常复杂,因为有很多符号和变化需要处理。

  • 有几种方法可以监视 DOM 的更改,我很确定可以构建一种立即恢复任何更改的机制,这与 Windows 的 DLL 管理非常相似。但它的构建将非常复杂并且非常耗费资源。

于 2010-04-20T08:44:31.390 回答
3

并不真地。JavaScript 是一种极其动态的语言,具有许多隐藏的或特定于浏览器的功能,可用于突破您可以设计的任何类型的监狱。

不要试图自己承担这个。考虑使用现有的“类似迷你 JS 的语言”项目,例如Caja

于 2010-04-20T08:59:45.160 回答
0

听起来您需要处理用户输入的数据并根据允许内容的白名单或黑名单替换无效标记。

于 2010-04-20T08:42:16.073 回答
0

你可以像 Facebook 那样做。他们正在预处理所有 javascript 源,为所有名称添加前缀,而不是他们自己的包装 API。

于 2010-04-20T08:57:42.840 回答
0

我有另一种方法:使用谷歌齿轮 WorkerPool api
见这个
http://code.google.com/apis/gears/api_workerpool.html

已创建的 worker 无权访问 DOM;像 document 和 window 这样的对象只存在于主页面上。这是工人不共享任何执行状态的结果。但是,worker 确实可以访问所有 J​​avaScript 内置函数。大多数 Gears 方法也可以通过自动定义的全局变量使用:google.gears.factory。(一个例外是 LocalServer 文件提交器,它需要 DOM。)对于其他功能,创建的工作人员可以要求主页执行请求。

于 2010-04-23T03:25:20.313 回答
0

为了实现沙箱,这种模式怎么样?

function safe(code,args)
{
    if (!args)
        args=[];
    return (function(){
    for (i in window) 
        eval("var "+i+";");
    return function(){return eval(code);}.apply(0,args);
    })();
}



ff=function()
{
    return 3.14;
}

console.log(safe("this;"));//Number
console.log(safe("window;"));//undefined
console.log(safe("console;"));//undefined
console.log(safe("Math;"));//MathConstructor
console.log(safe("JSON;"));//JSON
console.log(safe("Element;"));//undefined
console.log(safe("document;"));//undefined
console.log(safe("Math.cos(arguments[0]);",[3.14]));//-0.9999987317275395
console.log(safe("arguments[0]();",[ff]));//3.14

返回:

Number
undefined
undefined
MathConstructor
JSON
undefined
undefined
-0.9999987317275395
3.14 

你能提供一个适合攻击这个解决方案的漏洞吗?只是为了理解和提高我的知识,当然:)

谢谢!

于 2012-07-16T22:46:44.760 回答
0

现在,使用沙盒 IFrame 可以轻松实现这一点:

var codeFunction = function(x, y) {
    alert("Malicious code!");
    return x + y;
}

var iframe = document.createElement("iframe");
iframe.sandbox = "allow-scripts";
iframe.style.display = "none";
iframe.src = `data:text/html,
<script>
    var customFunction = ${codeFunction.toString()};
    window.onmessage = function(e) {
        parent.postMessage(customFunction(e.data.x, e.data.y), '*'); // Get arguments from input object
    }
</script>`;
document.body.appendChild(iframe);
iframe.onload = function() {
    iframe.contentWindow.postMessage({ // Input object
        x: 5,
        y: 6
    }, "*");
}
window.onmessage = function(e) {
    console.log(e.data); // 11
    document.body.removeChild(iframe);
}
于 2019-09-04T04:05:56.547 回答