2013-05-29 30 views
6

Tôi thường nghĩ phạm vi toàn cầu là không gian tên luôn có thể truy cập từ mọi nơi. Tôi muốn biết liệu về mặt lý thuyết có thể để ẩn hoàn toàn phạm vi toàn cầu hay không. Ví dụ, giả sử chúng ta có một số mã chúng tôi muốn eval uate (trong giao diện điều khiển của một trình duyệt):JavaScript - Cách ẩn phạm vi toàn cầu khỏi tập lệnh được đánh giá

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); 

By gói các eval cuộc gọi, thiswindow có thể được ẩn từ code:

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

Nhưng tôi không thể dừng việc tạo các biến toàn cầu một cách ngầm định. Có thể nào đó bằng cách nào đó? Tôi không muốn sử dụng thứ này, tôi chỉ tò mò thôi.

+1

Bạn đang cố gắng để sandbox 'eval''d/mã tùy ý? Có một cách tốt hơn xung quanh nếu đó là mục tiêu của bạn. –

+0

Không, tôi chỉ đang nghĩ đến việc che chắn phạm vi toàn cầu từ mã người dùng. Điều này dẫn tôi đến câu hỏi này, đó là về lý thuyết. – kol

+1

Sau đó, trong các trình duyệt hiện đại, về mặt lý thuyết, bạn có thể [đóng băng] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) đối tượng 'window'. Mặc dù tôi chưa bao giờ thử điều đó. –

Trả lời

7

Nếu bạn đang chạy trong các trình duyệt khá hiện đại, bạn hầu như có thể chặn window truy cập bằng cách làm cho một chức năng mà bóng tối của windowself biến với các thông số, và chạy mã trong chế độ nghiêm ngặt.

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. 

Bất kỳ cố gắng để truy cập window hay self chỉ sẽ truy cập vào đối tượng obj của chúng tôi, và giá trị của this cũng sẽ obj của chúng tôi.

Bởi vì chúng tôi đang ở chế độ nghiêm ngặt, nên không cho phép hình ảnh toàn cảnh ngầm. Ngoài ra, giá trị mặc định this của hàm sẽ là undefined thay vì window.

Tôi nghĩ rằng có một vài hacks có thể nhận được xung quanh này, nhưng điều này nên bao gồm hầu hết các kịch bản.

+1

Dường như bạn vẫn có thể truy cập các biến toàn cầu. 'code =" return location.href; ";', 'code =" trả về bàn điều khiển; ";', và 'code =" trả về đỉnh; ";' tất cả các kết quả trả về. – jongo45

+0

@ jongo45: Có, bạn có thể truy cập hình cầu, bởi vì chúng là toàn cầu. Nhưng bạn không thể thực hiện bất kỳ thao tác nào với phạm vi toàn cầu. Tôi khá chắc chắn OP đã cố gắng để ngăn chặn việc tạo ra các hình cầu mới, không chặn truy cập vào tất cả. –

+0

@squint: Không đúng, top.myfunc = "123"; cho phép bạn làm console.log (myfunc) sau khi mã đã được chạy. Nó sẽ lặp lại tất cả các biến toàn cục và biến chúng thành các đối số trước khi gọi mã. – Rahly

1

Tôi chấp nhận câu trả lời của @ squint, bởi vì tôi nghĩ việc sử dụng chế độ nghiêm ngặt là giải pháp.

Nhưng vấn đề cũng có thể được giải quyết mà không cần chế độ nghiêm ngặt. Trong trường hợp này, người ta có thể bộ nhớ cache biến toàn cục, eval mã, và ngay sau khi eval trở lại, xóa những globals mà không có một mục trong bộ nhớ cache (biến implcitly toàn cầu có thể bị xóa):

(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]; 
    } 
    } 
})(); 

Điều này không xử lý các trường hợp khi mã eval'd ghi đè lên một biến toàn cầu được tạo ra trước đó, hoàn toàn, nhưng tôi không nghĩ rằng nó không thể giải quyết này quá:

(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

Lưu ý: Đây vẫn là một công việc tiến bộ và một phần lấy cảm hứng từ đoạn mã của squint.

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 
    }; 
} 

Output kết quả (từ Firefox nháp):

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 
*/ 

Và một jsfiddle với một số kết quả.

Lưu ý: Một số kết quả không mong muốn hiển thị trong phần mềm nhưng không hiển thị trong các công cụ khác (tức làBiến số location trả về url của trang khi fiddle được xem từ aurora của firefox, nhưng không phải trên chrome hoặc trên bàn phím đầu tiên - có thể là công cụ của cơ chế __noSuchMethod__ hoặc tương tự 'cuối ràng buộc' của Firefox, dẫn đến các thuộc tính chỉ được thêm khi được truy cập).

Các vấn đề liên quan