javascript - 一个 "safe place"来评估 Javascript 中的受信任代码(具有特定上下文)? [编辑: how can you break it?]

标签 javascript scope eval

不要在标题上评判我,我知道 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);
}

一些变化的解释:
  • 在第一个版本中,我添加了 window 作为参数,因为在 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
  • 使用 non-alphanumeric Javascript expressions 构造字符串

  • 底线:您无法使用 Javascript 构建有效的沙箱。已经试过了;每一次尝试都是复杂的、脆弱的,并最终失败了。

    关于javascript - 一个 "safe place"来评估 Javascript 中的受信任代码(具有特定上下文)? [编辑: how can you break it?],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41544518/

    相关文章:

    javascript - 普通 JSON 到 GraphSON 格式

    javascript - 为什么输出屏幕中不显示端口号?

    python - 信号量变量如何传递到Python中的以下对象中?

    c++ - 声明静态可变值的正确方法是什么

    javascript - 如何在不使用 eval() 的情况下使用回调更新函数包装的 while 中的条件?

    javascript - 如何将 rel ="preload"用作 ="style"或 ="script"或提高页面速度的更好方法

    javascript - 选中复选框时如何显示/隐藏下拉菜单

    .net - 如何使用同一个 SqlConnection 对象在多个 SqlCommand 中声明和使用 T-SQL 变量来执行多次插入?

    python - 如何从 Python 中的被调用模块访问调用模块命名空间?

    lua - 说明 redis.call() 和 redis.pcall() 之间的区别