使WebWorkers成为一个安全的环境 [英] Making WebWorkers a safe environment

查看:137
本文介绍了使WebWorkers成为一个安全的环境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了让一个界面能够在浏览器中运行任意javascript代码,没有一个典型的妈妈玩笑的安全漏洞, Esailija 建议使用 Web工人的。它们在半沙盒环境中运行(没有DOM访问并且已经在浏览器中)并且可以被杀死,因此用户无法将它们置于无限循环中。

In a quest to have an interface capable of running arbitrary javascript code inside the browser, without having a security hole the size of a typical yo-mama joke, Esailija proposed using Web Workers. They run in a semi-sandboxed environment (no DOM access and already inside the browser) and can be killed so the user can't put them in an infinite loop.

以下是他提出的例子: http://tuohiniemi.fi/~runeli/petka/workertest。 html (打开你的控制台)

Here's the example he brought up: http://tuohiniemi.fi/~runeli/petka/workertest.html (open your console)

jsfiddle (仅限Google Chrome)

jsfiddle (Google chrome only)

现在,这似乎是一个很好的解决方案;然而,它是完整的(或接近完整的)吗?是否有任何明显缺失?

Now, this seems like a good solution; however, is it a complete (or approaching complete) one? Is there anything obvious missing?

整个事情(因为它连接到机器人)可以在github上找到: worker 评估者

The entire thing (as it's hooked up to a bot) can be found on github: worker, evaluator

main:

workercode = "worker.js";

function makeWorkerExecuteSomeCode( code, callback ) {
    var timeout;

    code = code + "";
    var worker = new Worker( workercode );

    worker.addEventListener( "message", function(event) {
        clearTimeout(timeout);
        callback( event.data );
    });

    worker.postMessage({
        code: code
    });

    timeout = window.setTimeout( function() {
        callback( "Maximum execution time exceeded" );
        worker.terminate();
    }, 1000 );
}

makeWorkerExecuteSomeCode( '5 + 5', function(answer){
    console.log( answer );
});

makeWorkerExecuteSomeCode( 'while(true);', function(answer){
    console.log( answer );
});

var kertoma = 'function kertoma(n){return n === 1 ? 1 : n * kertoma(n-1)}; kertoma(15);';

makeWorkerExecuteSomeCode( kertoma, function(answer){
    console.log( answer );
});

工人:

var global = this;

/* Could possibly create some helper functions here so they are always available when executing code in chat?*/

/* Most extra functions could be possibly unsafe */

    var wl = {
        "self": 1,
        "onmessage": 1,
        "postMessage": 1,
        "global": 1,
        "wl": 1,
        "eval": 1,
        "Array": 1,
        "Boolean": 1,
        "Date": 1,
        "Function": 1,
        "Number" : 1,
        "Object": 1,
        "RegExp": 1,
        "String": 1,
        "Error": 1,
        "EvalError": 1,
        "RangeError": 1,
        "ReferenceError": 1,
        "SyntaxError": 1,
        "TypeError": 1,
        "URIError": 1,
        "decodeURI": 1,
        "decodeURIComponent": 1,
        "encodeURI": 1,
        "encodeURIComponent": 1,
        "isFinite": 1,
        "isNaN": 1,
        "parseFloat": 1,
        "parseInt": 1,
        "Infinity": 1,
        "JSON": 1,
        "Math": 1,
        "NaN": 1,
        "undefined": 1
    };

    Object.getOwnPropertyNames( global ).forEach( function( prop ) {
        if( !wl.hasOwnProperty( prop ) ) {
            Object.defineProperty( global, prop, {
                get : function() {
                    throw new Error( "Security Exception: cannot access "+prop);
                    return 1;
                }, 
                configurable : false
            });    
        }
    });

    Object.getOwnPropertyNames( global.__proto__ ).forEach( function( prop ) {
        if( !wl.hasOwnProperty( prop ) ) {
            Object.defineProperty( global.__proto__, prop, {
                get : function() {
                    throw new Error( "Security Exception: cannot access "+prop);
                    return 1;
                }, 
                configurable : false
            });    
        }
    });




onmessage = function( event ) {
    "use strict";
    var code = event.data.code;
    var result;
    try {
        result = eval( '"use strict";\n'+code );
    }
    catch(e){
        result = e.toString();
    }
    postMessage( "(" + typeof result + ")" + " " + result );
};


推荐答案

当前代码(如下所列)现已进入在Stackoverflow javascript聊天室中使用了一段时间
到目前为止最棘手的问题是数组(5000000000).join(adasdadadasd)立刻崩溃了一些$ b当我运行代码执行器bot时,$ b浏览器选项卡。 Monkeypatching Array.prototype.join 似乎修复了这个问题,并且50ms的最大
执行时间适用于任何其他企图占用内存或崩溃浏览器的行为。

The current code (listed below) has been now in use in the Stackoverflow javascript chat room for a while and so far the toughest problem was Array(5000000000).join("adasdadadasd") instantly crashing some browser tabs for me when I was running the code executor bot. Monkeypatching Array.prototype.join seems to have fixed this and the maximum execution time of 50ms has worked for any other attempt to hog memory or crash the browser.

var global = this;

/* Could possibly create some helper functions here so they are always available when executing code in chat?*/

/* Most extra functions could be possibly unsafe */

var wl = {
    "self": 1,
    "onmessage": 1,
    "postMessage": 1,
    "global": 1,
    "wl": 1,
    "eval": 1,
    "Array": 1,
    "Boolean": 1,
    "Date": 1,
    "Function": 1,
    "Number" : 1,
    "Object": 1,
    "RegExp": 1,
    "String": 1,
    "Error": 1,
    "EvalError": 1,
    "RangeError": 1,
    "ReferenceError": 1,
    "SyntaxError": 1,
    "TypeError": 1,
    "URIError": 1,
    "decodeURI": 1,
    "decodeURIComponent": 1,
    "encodeURI": 1,
    "encodeURIComponent": 1,
    "isFinite": 1,
    "isNaN": 1,
    "parseFloat": 1,
    "parseInt": 1,
    "Infinity": 1,
    "JSON": 1,
    "Math": 1,
    "NaN": 1,
    "undefined": 1
};

Object.getOwnPropertyNames( global ).forEach( function( prop ) {
    if( !wl.hasOwnProperty( prop ) ) {
        Object.defineProperty( global, prop, {
            get : function() {
                throw "Security Exception: cannot access "+prop;
                return 1;
            }, 
            configurable : false
        });    
    }
});

Object.getOwnPropertyNames( global.__proto__ ).forEach( function( prop ) {
    if( !wl.hasOwnProperty( prop ) ) {
        Object.defineProperty( global.__proto__, prop, {
            get : function() {
                throw "Security Exception: cannot access "+prop;
                return 1;
            }, 
            configurable : false
        });    
    }
});

Object.defineProperty( Array.prototype, "join", {

    writable: false,
    configurable: false,
    enumerable: false,

    value: function(old){
        return function(arg){
            if( this.length > 500 || (arg && arg.length > 500 ) ) {
                throw "Exception: too many items";
            }

            return old.apply( this, arguments );
        };
    }(Array.prototype.join)

});


(function(){
    var cvalues = [];

    var console = {
        log: function(){
            cvalues = cvalues.concat( [].slice.call( arguments ) );
        }
    };

    function objToResult( obj ) {
        var result = obj;
        switch( typeof result ) {
            case "string":
                return '"' + result + '"';
                break;
            case "number":
            case "boolean":
            case "undefined":
            case "null":
            case "function":
                return result + "";
                break;
            case "object":
                if( !result ) {
                    return "null";
                }
                else if( result.constructor === Object || result.constructor === Array ) {
                    var type = ({}).toString.call( result );
                    var stringified;
                    try {
                        stringified = JSON.stringify(result);
                    }
                    catch(e) {
                        return ""+e;
                    }
                    return type + " " + stringified;
                }
                else {
                    return ({}).toString.call( result );
                }
                break;

        }

    }

    onmessage = function( event ) {
        "use strict";
        var code = event.data.code;
        var result;
        try {
            result = eval( '"use strict";\n'+code );
        }
        catch(e) {
            postMessage( e.toString() );
            return;
        }
        result = objToResult( result );
        if( cvalues && cvalues.length ) {
            result = result + cvalues.map( function( value, index ) {
                return "Console log "+(index+1)+":" + objToResult(value);
            }).join(" ");
        }
        postMessage( (""+result).substr(0,400) );
    };

})();

这篇关于使WebWorkers成为一个安全的环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆