(编辑此答案与您的预编辑问题有关。不知道使用 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 解析器,解析其代码并检查非法访问,然后才让代码运行。这是很多工作,但如果你的用例证明它是合理的......