2014-12-20 12 views
4

我避免使用eval()或從字符串創建的函數。但是當我需要運行一些可以由用戶輸入的Javascript子集時,我很想使用它,僅僅是因爲它能夠爲編寫詞法分析器/解析器和解釋器節省很多工作。將「with(...){...}」中的關鍵文字聲明爲在其中運行的沙箱代碼是否安全?

說我想運行此代碼:

a.toLowerCase() === 'xyz' || b == 1 || /pqr/.test(c) 

本土的辦法是將它傳遞到eval()這樣的:

with({a: ..., b: ..., c: ...}) { 
    ret = eval(code); 
} 

我不能肯定code總是包含非關鍵類似上面的代碼。這打開了運行惡意代碼的可能性。

我想傳遞一個對象重新定義臨界瀏覽器的對象到with除了像的實際數據:

var obj = { 
    // list incomplete ;) 
    console: true, XMLHttpRequest: true, document: true, window: true, addEventListener: true, removeEventListener: true, parent: true, top: true, history: true, ..., 

    // actual data 
    a: ..., b: ..., c: ... 
}; 

with (obj) { 
    ... 
} 

當內with訪問的對象/方法運行的代碼不possibe。

我知道如果通過另一個沒有重新定義的對象/函數間接訪問它們,仍然可以間接訪問這些方法。我們假設我也重新定義了這些。

對於作爲內容對象的對象和函數來說,沙盒代碼是否安全,其列表的內容是否足夠清單

在這種情況下,攻擊媒介將會剩下什麼?

編輯1:

的代碼應在Firefox,鉻,IE運行(10+),歌劇,Safari。

+0

它在哪裏運行?在用戶自己的瀏覽器中?在NodeJS中?在NodeJS或現代瀏覽器中,使用嚴格模式的IIFE會更好。 –

+0

讓每個用戶在自己的瀏覽器中運行自己的代碼。那裏什麼都不會出問題。 – Bergi

+0

[沙盒代碼的可能解決方案(這是一個鏈接)](http://stackoverflow.com/a/21700111/413180)。 – SilverlightFox

回答

7

不,這不安全。

不管你使用with代碼的執行環境做什麼,仍然可以使用下面的技巧來獲取「真正的」全局對象:

var window = (function(){ return this }).call(undefined); 

這工作,因爲Function.call將使用全局對象作爲this的值,如果它明確通過undefinednull

+0

他們甚至不需要'.call()'。只是'(function(){return this})()'會做同樣的事情。 –

+0

難道不能通過從正在被'eval'處理的字符串中刪除任何'function'來解決嗎? –

+0

@AlexisWilke:否。將黑名單錯誤的代碼從未正常工作。我的意思是,下一步將是'var window =(1,eval)(「this」);'。 – Bergi

4

如果陰影變量被刪除...

alert([1, window, document]); 
 

 
var obj = { 
 
    document: true, window: true 
 
}; 
 

 
with (obj) { 
 
    alert([2, window, document]); 
 
    
 
    delete window; 
 
    delete document; 
 
    
 
    alert([3, window, document]); //restored 
 
}

此外,如果你暴露任何DOM元素document/window對象可以通過ownerDocument/defaultView到達。

+0

難道這不能通過從正在'eval'的字符串中刪除任何'delete'來解決嗎? –

+1

你需要處理所有可能性,例如'eval(「de」+「lete document」);',如果你替換'eval',你需要禁止'new function'評估...它的零和遊戲你不能贏。 –

+0

但是,通過將變量定義爲不可配置,可以使變量免受「刪除」的影響。 – Bergi

0

您應該使用全局(和「靜態」)函數來避免訪問其他不需要的/私有變量(即一個子函數可以訪問父函數的所有變量)。

其次要從字符串中刪除幾個關鍵字來進行評估,以避免由duskwuff和Alex K.事情是這樣描述的問題:

function exec(e) 
{ 
    e = e.replace(/new/, "new_", "g") 
     .replace(/delete/, "delete_", "g") 
     .replace(/function/, "function_", "g") 
     .replace(/throw/, "throw_", "g") 
     .replace(/this/, "this_", "g") 
     .replace(/var/, "var_", "g") 
     .replace(/eval/, "eval_", "g"); 
    obj = { ... }; 
    with(obj) 
    { 
     eval(e); 
    } 
} 

注意,可能無法在嚴格模式下工作。正如Bergi在評論中提到的那樣,您還可以保護obj中的變量,並使它們不可刪除,因此您無法替換它們。

replace()可以包含更多的東西......您可能希望仔細觀察您嘗試實現的目標。如果預計評估字符串只是一個表達式,則應刪除所有關鍵字(不包括truefalsenull)。您可能還想刪除一些其他功能。這裏我只刪除了eval

如果你只想匹配單詞,所以單詞anew不匹配new你可以在正則表達式中使用\b flag。我不知道這個標記在瀏覽器上的兼容性如何。

e.replace(/\bnew\b/, "new_", "g"); 

這將匹配new但不anew

+1

如果一個字符串包含子字符串「new」,「delete」,...? –

+0

然後你可能不會得到正確的結果。您始終可以告訴最終用戶這些關鍵字是被禁止的。你也可以修復正則表達式。 –

+0

我做了一個更新,但很可能'\ b'在所有瀏覽器中都不起作用。 –

相關問題