ブラウザ内で任意の JavaScript コードを実行できるインターフェイスを、典型的な幼ママ ジョークほどの大きさのセキュリティ ホールを持たないものにするために、Esailja 氏はWeb Workersを使用することを提案しました。それらは半サンドボックス環境 (DOM アクセスなしで既にブラウザー内にある) で実行され、強制終了できるため、ユーザーはそれらを無限ループに入れることができません。
彼が持ち出した例を次に示します: http://tuohiniemi.fi/~runeli/petka/workertest.html (コンソールを開いてください)
jsfiddle (Google Chrome のみ)
さて、これは良い解決策のようです。しかし、それは完全な(または完全に近づいている)ものですか?明らかに欠けているものはありますか?
全体 (ボットに接続されているため) は github で見つけることができます: worker、evaluator
主要:
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 );
};