不要在标题上评判我,我知道 eval 是邪恶的,但我这样做是有原因的,而且会非常有限。事情是这样的:我想创建一个安全的空间,我可以在其中运行特定的(和受信任的)代码,并检索结果(如果它符合我的期望)。出于安全原因,我想将它从所有其他范围中删除(这个空间被要求提供结果,并且应该不能单独将任何内容导出到周围的范围)。
我找到了一个似乎可行的解决方案,它也可以为执行添加上下文,但我不确定它是否有效,或者该系统中是否存在安全漏洞。你能告诉我它是否有问题吗?
它实际上创建了与全局变量同名的本地变量,以防止访问它们。它还剥离了功能(我将添加功能以保留我想要保留的功能)。该函数声明为最接近全局变量,以避免更高的局部范围的可见性(计划删除这些特定局部变量的参数)。
function contextNoScope(root, context) {
//I had to pass window as parameter for it to work properly
for(var key in root){
if(key != '0' && key != 'window'){
eval('var ' + key + '=undefined;');
}
}
var window = undefined;
var root = undefined; //root has to be forbidden too
return function() {
this.eval = function(str){ return eval(str); };
return this;
}.call(context);
}
用法:
(function(root){
function contextNoScope(root, context) {
//...same as previous
}
var context = { x: 3 };
var space = contextNoScope(root, context);
console.log(space.eval('this.x + 1'));
})(window);
(注意:如果您以全局方式测试此代码,如果您为上下文传递全局变量,请不要忘记添加特殊修复,因为它将像所有其他变量一样被屏蔽。如果还必须添加修复您想尝试将 window 作为上下文参数传递,原因很明显..)
编辑:
为了更清楚地了解脚本的作用以及可以解决我的问题的方法:我假设 JS 中没有完全安全的东西可以称为“受信任的源”,因为我们显然在这里谈论的是导入脚本。受信任是指将首先检查脚本来源并添加安全 key 。
每个脚本都从给定的上下文中获取一个特定的变量,并为其添加一个属性。这里的名字是给定的,意味着我们事先知道哪个 var 将被修改,以及添加到它的属性的名称和类型是什么。在某种程度上,我已经可以检查所做的事情是否是有意的,这里的问题是“确定”任何代码都不能主要干扰事件或 DOM,并且不会删除或修改任何内容在给定的上下文中,除了添加属性..
编辑2:请打破它!
(我还不是所有网站规则的专家,如果这不是正确编辑的方法,请纠正我:我选择不修改第一个代码并添加新版本,即使它有点长。)
我正在为我的解决方案寻找一个合适的沙箱,由比我更好的人制作,但是因为我很好奇并想继续学习,我在这里发布了我所做的改进版本,因为我想知道这仍然可以坏掉。所以我现在正在寻找可以打破这个系统的精确技巧:
function contextNoScope(context) {
var len, i, keys, val, window = root, isNaN = root.isNaN, console = root.console;
if(!context){ context = {}; }
keys = Object.getOwnPropertyNames(window);
if(len = keys.length){
for(i = 0; i < len; i++){
val = keys[i];
//TODO: remove 'console' from the if (debug purpose)
if(isNaN(val) && val != 'window' && val != 'eval' && val != 'isNaN' && val != 'console'){
eval('var ' + val + '=undefined;');
}
}
}
isNaN = undefined;
len = undefined;
i = undefined;
keys = undefined;
val = undefined;
eval('var root = undefined');
return function() {
this.eval = function(str){
if(str){
str = str.toString();
//TODO: replace by more relevant regex (it currently throws error for words like 'evaluation')
if(str.indexOf('constructor') > -1 || str.indexOf('__proto__') > -1 || str.indexOf('prototype') > -1 || str.indexOf('eval') > -1){
console.log('ERROR - str contains forbidden code "constructor", "__proto__", "eval", "prototype"', '\n' + str);
return false;
}
try{
eval(str);
return true;
}catch(e){
console.log(e + '\nin:\n' + str);
return false;
}
}
console.log('ERROR - str is not defined: ', str);
return false;
};
return this;
}.call(context);
}
一些变化的解释:
var
时出现了一个基本错误。已评估,没有必要。但是将 window 作为另一个名称(此处为“root”)传递似乎更容易。整个函数的包装方式与第一个版本的用法相同。 getOwnPropertyNames
还可以获得不可枚举的属性,但我知道向后兼容性问题,这不是我所说的“破坏系统”以使用旧浏览器的意思(我已经知道了)isNaN(val)
的测试此处不将引用 i 帧 eval('var root = undefined');
是在行执行时创建 var 的技巧,而不是在开始时创建,就像使用常规 var
一样alert(1)
,它不起作用)最佳答案
Function.apply(undefined)
可以破坏任何基于将变量设置为影子全局变量的内容。 ,它使用 this
运行函数设置为全局上下文。例如:
(function() {
this.alert(1);
}).apply(undefined);
任何基于正则表达式的东西都可能被以下组合破坏:
new Function
, eval
等底线:您无法使用 Javascript 构建有效的沙箱。已经试过了;每一次尝试都是复杂的、脆弱的,并最终失败了。
关于javascript - 一个 "safe place"来评估 Javascript 中的受信任代码(具有特定上下文)? [编辑: how can you break it?],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41544518/