2009-02-12 39 views
29

Tôi có tệp javascript đọc tệp khác có thể chứa các đoạn javascript cần phải là eval() - ed. Các đoạn script được cho là phù hợp với một tập con javascript nghiêm ngặt giới hạn những gì chúng có thể làm và biến nào chúng có thể thay đổi, nhưng tôi muốn biết nếu có một số cách để thực thi điều này bằng cách ngăn không cho eval thấy các biến trong phạm vi toàn cầu . Một cái gì đó như sau:Hạn chế eval() đến phạm vi hẹp

function safeEval(fragment) 
{ 
    var localVariable = g_Variable; 

    { 
     // do magic scoping here so that the eval fragment can see localVariable 
     // but not g_Variable or anything else outside function scope 

     eval(fragment); 
    } 
} 

Mã thực tế không cần phải như thế này - Tôi mở cửa cho bất kỳ và tất cả các thủ thuật kỳ lạ với đóng cửa, vv Nhưng tôi muốn biết nếu điều này thậm chí là có thể.

+0

Tôi không biết liệu nó sẽ làm việc cho 'eval' nhưng bạn có thể cố gắng để chuyển đổi ngữ cảnh thực thi của nó (đối tượng kích hoạt google). – jfs

+0

Hãy xem triển khai thực hiện dojox.secure.sandbox. – jfs

+0

Bây giờ, những gì bạn có thể muốn là một Web Worker. – bjb568

Trả lời

50

Câu trả lời ngắn: Không. Nếu trong phạm vi toàn cầu, nó có sẵn cho mọi thứ.

dài câu trả lời: nếu bạn eval() ing mã không tin cậy rằng thực sự muốn đọc hoặc gây rối với môi trường thực thi của bạn, bạn đang hơi say. Nhưng nếu bạn sở hữu và tin tưởng tất cả các mã được thực thi, trong đó có việc eval() ed, bạn có thể giả mạo nó bằng cách ghi đè bối cảnh thực hiện:

function maskedEval(scr) 
{ 
    // set up an object to serve as the context for the code 
    // being evaluated. 
    var mask = {}; 
    // mask global properties 
    for (p in this) 
     mask[p] = undefined; 

    // execute script in private context 
    (new Function("with(this) { " + scr + "}")).call(mask); 
} 

Một lần nữa, tôi phải nhấn mạnh:

này sẽ chỉ phục vụ để che chắn tin cậy mã từ ngữ cảnh được thực thi. Nếu bạn không tin cậy mã, KHÔNG ĐƯỢC eval() (hoặc chuyển nó đến số Function() mới hoặc sử dụng mã theo bất kỳ cách nào khác hoạt động như eval()).

+0

Có một hình ảnh nhỏ với phương thức 'with' đã cắn tôi trước đây. Các hàm được khai báo bên trong khối không có quyền truy cập vào đích của câu lệnh. –

+0

Vâng, tôi mong đợi một chức năng * khai báo * có thể được "treo" trong trường hợp đó - bạn muốn dính vào các biểu thức. – Shog9

+0

chết tiệt .... tôi không thể nói tôi hạnh phúc thế nào: D thật tuyệt vời !! bây giờ tôi có thể hoàn thành mẫu của tôi-động cơ ... phải kiểm tra nhiều hơn, nhưng tôi nghĩ rằng tôi đã có tất cả ... chết tiệt ... thats người đàn ông khá mát mẻ ... bạn biết ... để phân tích các biểu thức nạp từ mẫu là khó , nhưng với điều này khá dễ dàng: D Bạn có biết bất kỳ rò rỉ bảo mật nào không? tôi không bao giờ biết điều này "với (điều này)" ... tôi biết rằng tôi phải kiểm tra vor keaywords, để loại bỏ tiêm ác: D – Mephiztopheles

2

Bạn không thể giới hạn phạm vi eval

btw thấy this post

Có thể có một số cách khác để thực hiện những gì nó là bạn muốn đạt được trong chương trình lớn của sự vật nhưng bạn không thể giới hạn phạm vi eval bằng mọi cách. Bạn có thể ẩn các biến nhất định dưới dạng biến riêng tư trong javascript, nhưng tôi không nghĩ đây là những gì bạn đang làm.

2

Đây là một ý tưởng. Điều gì sẽ xảy ra nếu bạn đã sử dụng một trình phân tích tĩnh (ví dụ: bạn có thể xây dựng ví dụ esprima) để xác định các biến bên ngoài mà mã eval'd sử dụng và bí danh chúng. Bởi "mã bên ngoài", tôi có nghĩa là các biến mã được đánh giá là sử dụng nhưng không khai báo.Dưới đây là một ví dụ:

eval(safeEval(
    "var x = window.theX;" 
    +"y = Math.random();" 
    +"eval('window.z = 500;');")) 

nơi safeEval trả về chuỗi javascript sửa đổi với một bối cảnh đó ngăn chặn truy cập đến các biến bên ngoài:

";(function(y, Math, window) {" 
    +"var x = window.theX;" 
    +"y = Math.random();" 
    +"eval(safeEval('window.z = 500;');" 
"})();" 

Có một vài điều bạn có thể làm bây giờ với điều này:

  • Bạn có thể đảm bảo rằng mã eval'd không thể đọc các giá trị của các biến bên ngoài, cũng không viết cho chúng (bằng cách chuyển undefined làm đối số hàm, hoặc không chuyển đối số). Hoặc bạn có thể chỉ cần ném một ngoại lệ trong trường hợp các biến được truy cập không an toàn.
  • Bạn cũng đảm bảo rằng các biến được tạo ra bởi eval không ảnh hưởng đến phạm vi xung quanh
  • Bạn có thể cho phép eval để tạo ra các biến trong phạm vi xung quanh bằng cách tuyên bố các biến ngoài việc đóng cửa thay vì như chức năng thông số
  • Bạn có thể cho phép truy cập chỉ đọc bởi sao chép giá trị của biến bên ngoài và sử dụng chúng như các đối số cho hàm
  • Bạn có thể cho phép đọc-ghi truy cập vào các biến cụ thể bằng cách nói safeEval để không bí danh những cái tên đặc biệt
  • Bạn có thể phát hiện trường hợp eval thực hiện không sửa đổi một biến cụ thể và cho phép nó tự động bị loại trừ khỏi bị bí danh (ví dụ: Toán trong trường hợp này, không được sửa đổi)
  • Bạn có thể cung cấp cho các eval một bối cảnh trong đó để chạy, bằng cách thông qua các giá trị lập luận rằng có thể khác nhau so với bối cảnh xung quanh
  • Bạn có thể nắm bắt được những thay đổi bối cảnh bởi cũng trả về các đối số hàm từ hàm để bạn có thể kiểm tra chúng bên ngoài eval.

Lưu ý rằng việc sử dụng eval là một trường hợp đặc biệt, vì bởi bản chất của nó, nó có hiệu quả có thể không được bao bọc trong chức năng khác (đó là lý do tại sao chúng ta phải làm eval(safeEval(...))).

Tất nhiên, làm tất cả công việc này có thể làm chậm mã của bạn, nhưng chắc chắn có những nơi mà lượt truy cập không thành vấn đề. Hy vọng điều này sẽ giúp một ai đó. Và nếu ai đó tạo ra một bằng chứng về khái niệm, tôi rất muốn nhìn thấy một liên kết đến nó ở đây;)

1

Không sử dụng eval. Có một cách khác, js.js: JS interpreter written in JS, để bạn có thể chạy các chương trình JS trong bất kỳ môi trường nào bạn đã quản lý để thiết lập. Dưới đây là ví dụ về API của trang từ trang dự án:

var jsObjs = JSJS.Init(); 
var rval = JSJS.EvaluateScript(jsObjs.cx, jsObjs.glob, "1 + 1"); 
var d = JSJS.ValueToNumber(jsObjs.cx, rval); 
window.alert(d); // 2 
JSJS.End(jsObjs); 

Không có gì đáng sợ, như bạn có thể thấy.

+0

3MB và chỉ 594KB sau khi nén gzip – prototype

+0

@ user645715 1) Thử sử dụng Trình biên dịch đóng gói để nén thậm chí nhiều hơn. 2) Có sự sụt giảm 200x, điều này còn tệ hơn nhiều so với mã nguồn 3MB. 3) Chưa có giải pháp nào khác. –

1

Tương tự như kịch bản lệnh chức năng động trong phương pháp chặn with ở trên, điều này cho phép bạn thêm pseudo-globals vào mã bạn muốn thực thi. Bạn có thể "ẩn" những thứ cụ thể bằng cách thêm chúng vào ngữ cảnh.

function evalInContext(source, context) { 
    source = '(function(' + Object.keys(context).join(', ') + ') {' + source + '})'; 

    var compiled = eval(source); 

    return compiled.apply(context, values()); 

    // you likely don't need this - use underscore, jQuery, etc 
    function values() { 
     var result = []; 
     for (var property in context) 
      if (context.hasOwnProperty(property)) 
       result.push(context[property]); 
     return result; 
    } 
} 

Xem http://jsfiddle.net/PRh8t/ để biết ví dụ. Lưu ý rằng Object.keys không được hỗ trợ trong tất cả các trình duyệt.

0

Không thực thi mã bạn không tin tưởng. Globals sẽ luôn có thể truy cập được. Nếu bạn làm điều tin tưởng vào mã, bạn có thể thực hiện nó với các biến đặc biệt trong đó là phạm vi như sau:

(new Function("a", "b", "alert(a + b);"))(1, 2); 

này tương đương với:

(function (a, b) { 
    alert(a + b); 
})(1, 2); 
0

trả lời Shog9 ♦ 's là rất tốt. Nhưng nếu mã của bạn chỉ là một biểu thức, mã sẽ được thực hiện và không có gì sẽ được trả lại. Đối với biểu thức, sử dụng

function evalInContext(context, js) { 

    return eval('with(context) { ' + js + ' }'); 

} 

Dưới đây là làm thế nào để sử dụng nó:

var obj = {key: true}; 

evalInContext(obj, 'key ? "YES" : "NO"'); 

Nó sẽ trở lại "YES".

Nếu bạn không chắc chắn nếu mã được thực thi là biểu hiện hoặc báo cáo, bạn có thể kết hợp chúng:

function evalInContext(context, js) { 

    var value; 

    try { 
    // for expressions 
    value = eval('with(context) { ' + js + ' }'); 
    } catch (e) { 
    if (e instanceof SyntaxError) { 
     try { 
     // for statements 
     value = (new Function('with(this) { ' + js + ' }')).call(context); 
     } catch (e) {} 
    } 
    } 

    return value; 
} 
Các vấn đề liên quan