2013-05-29 7 views
6

私は通常グローバルスコープをどこからでもアクセスできる名前空間と考えています。理論的にはが完全に非表示にできるかどうかを知りたいです。グローバルスコープ。例えば、我々は(ブラウザのコンソールに)にeval uateをしたいと思い、我々はいくつかのコードを持っていると仮定します。JavaScript - evalされたスクリプトからグローバルスコープを非表示にする方法

var code = 
    "console.log(this); " + // access the global object directly 
    "console.log(window); " + // access the global object as the window object 
    "newGlobalVar = 42; "; // implicitly create global object 
eval(code); 

eval呼び出しをラップすることにより、thiswindowcodeから隠すことができます。

(function (window) { eval(code); }).call({}); 

しかし、私はcodeが暗黙的にグローバル変数を作成するのを止めることができません。どういうわけか可能ですか?私はこのものを使用したくない、私はちょうど興味がある。

+1

'eval''d /任意のコードをサンドボックスしようとしていますか?それがあなたの目的なら、より良い方法があります。 –

+0

いいえ、私はちょうどユーザーコードからグローバルスコープを遮蔽することを考えていました。これは私にこの質問につながりました。理論についてです。 – kol

+1

それから、現代​​のブラウザでは、理論的に、 'window'オブジェクトを(フリーズして)(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)できます。私はそれを試みたことはありませんが。 –

答えて

7

あなたはかなり近代的なブラウザで実行している場合、あなたはほとんどのパラメータでwindowself変数をシャドウ、そしてstrictモードでコードを実行機能を作ることによってwindowアクセスをブロックすることができます。

var obj = {}; 

var func = new Function("self", "window", "'use strict';" + code); 

func.call(obj, obj, obj); 

console.log(obj); // see if there were any attempts to set global variables. 

windowまたはselfにアクセスしようとすると、単に私たちのobjオブジェクトにアクセスし、thisの値も、当社objになります。

私たちは厳密なモードなので、暗黙的なグローバルは許可されません。また、デフォルトのthisの値はの代わりにundefinedになります。

私は、これを回避することができるいくつかのハックがあると思いますが、これはほとんどのシナリオをカバーするはずです。

+1

それでもグローバル変数にアクセスすることができます。 'code =" return location.href; ";'、 'code ="戻りコンソール; ";'、 'code =" return top; ";'返されたすべての結果。 – jongo45

+0

@ jongo45:はい、グローバルであるため、グローバルにアクセスできます。しかし、あなたはグローバルスコープに対して何も操作することはできません。私はOPがすべての人へのアクセスをブロックするのではなく、新しいグローバルの作成を阻止しようとしていたと確信しています。 –

+0

@squint:そうではありません、top.myfunc = "123";コード実行後にconsole.log(myfunc)を実行できます。コードを呼び出す前に、すべてのグローバル変数を反復して引数にする必要があります。 – Rahly

1

私は@ squintの答えを受け入れました。厳密なモードを使用することが解決策だと思います。

しかし、この問題は厳密なモードなしでも解決できます。 evalが返された後、この場合は、1がキャッシュ内のエントリを持っていないそれらのグローバルを削除し、グローバル変数、evalコード、および権利をキャッシュすることができます(implcitlyグローバル変数を削除することができます):

(function() { 
    var cache = []; 
    for (var prop in this) { 
    if (this.hasOwnProperty(prop)) { 
     cache.push(prop); 
    } 
    } 
    (function (window) { try { eval(code); } catch (e) { } }).call({}); 
    for (var prop in this) { 
    if (this.hasOwnProperty(prop) && cache[prop] === undefined) { 
     var success = delete this[prop]; 
    } 
    } 
})(); 

eval'dコードは、以前に作成した、暗黙のうちにグローバル変数を上書きする場合は、このケースを処理しませんが、私はそれがあまりにもこの問題を解決することは不可能だとは思わない:

(function() { 
    var cache = {}; 
    for (var prop in this) { 
    if (this.hasOwnProperty(prop)) { 
     cache[prop] = this[prop]; 
    } 
    } 
    (function (window) { try { eval(code); } catch (e) { } }).call({}); 
    for (var prop in this) { 
    if (this.hasOwnProperty(prop)) { 
     var success = delete this[prop]; 
     if (success && cache[prop] !== undefined) { 
     this[prop] = cache[prop]; 
     } 
    } 
    } 
})(); 
4

注:これは仕事にまだありますスケートのコードスニペットに部分的に触発されています。 (Firefoxのスクラッチパッドから)

function quarantinedFunction(fnText){ 
    var exceptionKeys=[ 
     "eval","Object", //need exceptions for this else error. (ie, 'Exception: redefining eval is deprecated') 
     "Number","String","Boolean","RegExp","JSON","Date", 
    ]; 
    var forbiddenKeys=[ 
     "fn","fnText","forbiddenKeys","exceptionKeys","empty","oForbiddenKeys", 
    ]; 
    var oForbiddenKeys=Object.create(null); 
    var empty=Object.create(null); 
    Object.freeze(empty); 
    forbiddenKeys.forEach(function(key){ 
     oForbiddenKeys[key]=null; 
    }); 
    [this,self].forEach(function(obj){ 
     Object.getOwnPropertyNames(obj).forEach(function(key){ 
      if(!key.match(/^[\$\w]+$/))return; 
      oForbiddenKeys[key]=null; 
     }); 
    }); 
    exceptionKeys.forEach(function(key){ 
     delete oForbiddenKeys[key]; 
    }); 

    if(0){//debugging. 
     return function(){ 
      return Object.keys(oForbiddenKeys); 
      return Object.keys(empty); 
     }; 
    } 

    fnText=[ 
     '"use strict";', 
     "var "+Object.keys(oForbiddenKeys).join(", ")+";", 
     "{", 
     fnText, 
     "}" 
    ].join("\n"); 

    var fn= (function(){ 
     with(empty) 
     { 
      return new Function("self","window",fnText); 
     } 
    })(); 

    return function(){ 
     return fn.call(Object.create(null));  //self,window undefined 
     return fn.call(empty,empty,empty); //self,window are objects w/o properties 
    }; 
} 

出力結果:

quarantinedFunction("return location.href;")(); 
/* 
Exception: location is undefined 
*/ 
quarantinedFunction("someGlobalVar=15;")(); 
/* 
Exception: assignment to undeclared variable someGlobalVar 
*/ 
quarantinedFunction("return 9*9;")(); 
/* 
81 
*/ 
quarantinedFunction("return console;")(); 
/* 
undefined 
*/ 

そして、いくつかの結果をjsfiddle

注:予期しない結果は、フィドルには表示されますが、他のツールでは表示されません。location変数は、Firefoxのオーロラからフィーダを見るとページのURLを返しますが、chromeやscratchpad devtoolでは表示されません - おそらくFirefoxの__noSuchMethod__や同様の 'late-binding'メカニズムの手作業によってアクセスされたときにのみプロパティが追加されます)。

関連する問題