Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可以对浏览器中运行的JavaScript进行沙箱处理?_Javascript_Browser_Sandbox - Fatal编程技术网

是否可以对浏览器中运行的JavaScript进行沙箱处理?

是否可以对浏览器中运行的JavaScript进行沙箱处理?,javascript,browser,sandbox,Javascript,Browser,Sandbox,我想知道是否有可能对浏览器中运行的JavaScript进行沙箱处理,以防止访问HTML页面中运行的JavaScript代码通常可用的功能 例如,假设我想为最终用户提供一个JavaScript API,让他们定义在“有趣的事件”发生时运行的事件处理程序,但我不想让这些用户访问窗口对象的属性和函数。我能做到吗 在最简单的情况下,假设我想阻止用户调用alert。我能想到的几种方法是: 重新定义窗口。全局警报。我认为这不是一种有效的方法,因为页面中运行的其他代码(即,不是用户在其事件处理程序中编写的内

我想知道是否有可能对浏览器中运行的JavaScript进行沙箱处理,以防止访问HTML页面中运行的JavaScript代码通常可用的功能

例如,假设我想为最终用户提供一个JavaScript API,让他们定义在“有趣的事件”发生时运行的事件处理程序,但我不想让这些用户访问
窗口
对象的属性和函数。我能做到吗

在最简单的情况下,假设我想阻止用户调用
alert
。我能想到的几种方法是:

  • 重新定义
    窗口。全局警报
    。我认为这不是一种有效的方法,因为页面中运行的其他代码(即,不是用户在其事件处理程序中编写的内容)可能希望使用
    警报
  • 将事件处理程序代码发送到服务器进行处理。我不确定将代码发送到服务器进行处理是否正确,因为事件处理程序需要在页面的上下文中运行

服务器处理用户定义的函数,然后生成要在客户机上执行的回调,这样的解决方案是否可行?即使这种方法有效,还有更好的方法来解决这个问题吗?

您可以将用户的代码封装在一个函数中,该函数将禁用对象重新定义为参数——调用时这些对象将是未定义的:

(function (alert) {

alert ("uh oh!"); // User code

}) ();
当然,聪明的攻击者可以通过检查JavaScript DOM并找到包含窗口引用的非重写对象来绕过此问题



另一个想法是使用类似的工具扫描用户代码。确保设置为没有预设变量(或:仅包含您想要的变量),然后如果设置或访问了任何全局变量,则不要使用用户的脚本。同样,它可能很容易遍历DOM——用户可以使用文本构造的对象可能具有对窗口对象的隐式引用,可以通过访问这些对象来逃离沙箱。

此用户JavaScript代码来自何处

对于用户将代码嵌入到页面中,然后从浏览器调用页面,您无能为力(请参阅)。这只是浏览器所做的事情

但是,如果您将脚本存储在数据库中,然后检索它并对其进行eval(),则可以在脚本运行之前对其进行清理

删除所有窗口的代码示例。和文件。参考资料:

 eval(
  unsafeUserScript
    .replace(/\/\/.+\n|\/\*.*\*\/, '') // Clear all comments
    .replace(/\s(window|document)\s*[\;\)\.]/, '') // Removes window. Or window; or window)
 )
这将尝试阻止执行(未测试)以下操作:


您必须对不安全的用户脚本应用很多限制。不幸的是,没有任何“沙盒容器”可用于JavaScript。

所有浏览器供应商和HTML5规范都在努力实现一个实际的沙盒属性,以允许沙盒iframe——但它仍然限于iframe粒度

一般来说,任何程度的正则表达式等都不能安全地清除任意用户提供的JavaScript,因为它会退化为停止问题:-/

是一个源到源转换器,“允许您将不受信任的第三方HTML和JavaScript内联到页面中,并且仍然是安全的。”

  • 假设您有代码要执行:

     var sCode = "alert(document)";
    
    现在,假设您想在沙箱中执行它:

     new Function("window", "with(window){" + sCode + "}")({});
    
    这两行在执行时将失败,因为“沙盒”中没有“警报”功能

  • 现在,您希望使用您的功能公开window对象的一个成员:

     new Function("window", "with(window){" + sCode + "}")({
         'alert':function(sString){document.title = sString}
     });
    

  • 事实上,你可以添加引号并进行其他润色,但我想想法很清楚。

    看看:

    ADsafe可以安全地将来宾代码(如第三方脚本广告或小部件)放在任何网页上。ADsafe定义了JavaScript的一个子集,其功能强大到允许来宾代码执行有价值的交互,同时防止恶意或意外的损坏或入侵。ADsafe子集可以通过JSLint等工具进行机械验证,这样就不需要人为检查来检查来宾代码的安全性。ADsafe子集还实施了良好的编码实践,增加了来宾代码正确运行的可能性


    通过查看中的
    template.html
    template.js
    文件,您可以看到一个如何使用ADsafe的示例。

    我一直在开发一个简化的JavaScript沙盒,让用户为我的站点构建小程序。尽管我在允许DOM访问方面仍然面临一些挑战(parentNode只是不让我保持安全=/),但我的方法只是用一些有用/无害的成员重新定义window对象,然后使用这个重新定义的窗口作为默认范围来评估用户代码

    我的“核心”代码是这样的。。。(我没有完全展示;)

    因此,我可以实例化一个沙箱并使用其execute()函数来运行代码。此外,eval’d代码中所有新声明的变量最终都将绑定到execute()范围,因此不会出现名称冲突或与现有代码混淆的情况


    尽管全局对象仍然可以访问,但那些沙盒代码不知道的对象必须在Sandbox::scope对象中定义为代理。

    我创建了一个名为的沙盒库,该库使用web workers来沙盒代码。它还有一个输入方法,用于显式地提供沙盒代码数据,否则无法获得这些数据

    以下是API的一个示例:

    jsandbox
        .eval({
          code    : "x=1;Math.round(Math.pow(input, ++x))",
          input   : 36.565010597564445,
          callback: function(n) {
              console.log("number: ", n); // number: 1337
          }
      }).eval({
          code   : "][];.]\\ (*# ($(! ~",
          onerror: function(ex) {
              console.log("syntax error: ", ex); // syntax error: [error object]
          }
      }).eval({
          code    : '"foo"+input',
          input   : "bar",
          callback: function(str) {
              console.log("string: ", str); // string: foobar
          }
      }).eval({
          code    : "({q:1, w:2})",
          callback: function(obj) {
              console.log("object: ", obj); // object: object q=1 w=2
          }
      }).eval({
          code    : "[1, 2, 3].concat(input)",
          input   : [4, 5, 6],
          callback: function(arr) {
              console.log("array: ", arr); // array: [1, 2, 3, 4, 5, 6]
          }
      }).eval({
          code    : "function x(z){this.y=z;};new x(input)",
          input   : 4,
          callback: function(x) {
              console.log("new x: ", x); // new x: object y=4
          }
      });
    

    一种丑陋的方式,但也许这对你有用:

    我获取了所有全局变量,并在沙盒范围内重新定义了它们,还添加了严格模式,因此它们无法使用匿名函数获取全局对象

    function construct(constructor, args) {
      function F() {
          return constructor.apply(this, args);
      }
      F.prototype = constructor.prototype;
      return new F();
    }
    // Sanboxer
    function sandboxcode(string, inject) {
      "use strict";
      var globals = [];
      for (var i in window) {
        // <--REMOVE THIS CONDITION
        if (i != "console")
        // REMOVE THIS CONDITION -->
        globals.push(i);
      }
      globals.push('"use strict";\n'+string);
      return construct(Function, globals).apply(inject ? inject : {});
    }
    sandboxcode('console.log( this, window, top , self, parent, this["jQuery"], (function(){return this;}()));');
    // => Object {} undefined undefined undefined undefined undefined undefined
    console.log("return of this", sandboxcode('return this;', {window:"sanboxed code"}));
    // => Object {window: "sanboxed code"}
    
    函数构造(构造函数、参数){
    函数F(){
    返回构造函数。应用(此参数为args);
    }
    F.prototype=constructor.prototype;
    返回新的F();
    }
    //桑博克瑟
    函数sandboxcode(字符串,注入){
    “使用stric
    
    jsandbox
        .eval({
          code    : "x=1;Math.round(Math.pow(input, ++x))",
          input   : 36.565010597564445,
          callback: function(n) {
              console.log("number: ", n); // number: 1337
          }
      }).eval({
          code   : "][];.]\\ (*# ($(! ~",
          onerror: function(ex) {
              console.log("syntax error: ", ex); // syntax error: [error object]
          }
      }).eval({
          code    : '"foo"+input',
          input   : "bar",
          callback: function(str) {
              console.log("string: ", str); // string: foobar
          }
      }).eval({
          code    : "({q:1, w:2})",
          callback: function(obj) {
              console.log("object: ", obj); // object: object q=1 w=2
          }
      }).eval({
          code    : "[1, 2, 3].concat(input)",
          input   : [4, 5, 6],
          callback: function(arr) {
              console.log("array: ", arr); // array: [1, 2, 3, 4, 5, 6]
          }
      }).eval({
          code    : "function x(z){this.y=z;};new x(input)",
          input   : 4,
          callback: function(x) {
              console.log("new x: ", x); // new x: object y=4
          }
      });
    
    function construct(constructor, args) {
      function F() {
          return constructor.apply(this, args);
      }
      F.prototype = constructor.prototype;
      return new F();
    }
    // Sanboxer
    function sandboxcode(string, inject) {
      "use strict";
      var globals = [];
      for (var i in window) {
        // <--REMOVE THIS CONDITION
        if (i != "console")
        // REMOVE THIS CONDITION -->
        globals.push(i);
      }
      globals.push('"use strict";\n'+string);
      return construct(Function, globals).apply(inject ? inject : {});
    }
    sandboxcode('console.log( this, window, top , self, parent, this["jQuery"], (function(){return this;}()));');
    // => Object {} undefined undefined undefined undefined undefined undefined
    console.log("return of this", sandboxcode('return this;', {window:"sanboxed code"}));
    // => Object {window: "sanboxed code"}
    
    function safeEval(untrustedCode)
    {
        return new Promise(function (resolve, reject)
            {
                var blobURL = URL.createObjectURL(new Blob([
                    "(",
                    function ()
                    {
                        var _postMessage = postMessage;
                        var _addEventListener = addEventListener;
    
                        (function (obj)
                        {
                            "use strict";
    
                            var current = obj;
                            var keepProperties =
                            [
                                // Required
                                'Object', 'Function', 'Infinity', 'NaN', 'undefined', 'caches', 'TEMPORARY', 'PERSISTENT',
                                // Optional, but trivial to get back
                                'Array', 'Boolean', 'Number', 'String', 'Symbol',
                                // Optional
                                'Map', 'Math', 'Set',
                            ];
    
                            do
                            {
                                Object.getOwnPropertyNames(current).forEach(function (name)
                                {
                                    if (keepProperties.indexOf(name) === -1)
                                    {
                                        delete current[name];
                                    }
                                });
    
                                current = Object.getPrototypeOf(current);
                            }
                            while (current !== Object.prototype)
                                ;
    
                        })(this);
    
                        _addEventListener("message", function (e)
                        {
                            var f = new Function("", "return (" + e.data + "\n);");
                            _postMessage(f());
                        });
                    }.toString(),
                    ")()"],
                    {type: "application/javascript"}));
    
                    var worker = new Worker(blobURL);
    
                    URL.revokeObjectURL(blobURL);
    
                    worker.onmessage = function (evt)
                    {
                        worker.terminate();
                        resolve(evt.data);
                    };
    
                    worker.onerror = function (evt)
                    {
                        reject(new Error(evt.message));
                    };
    
                    worker.postMessage(untrustedCode);
    
                    setTimeout(function ()
                    {
                        worker.terminate();
                        reject(new Error('The worker timed out.'));
                    }, 1000);
            });
    }
    
    var promise = safeEval("1+2+3");
    
    promise.then(function (result) {
                     alert(result);
                 });