2014-03-19 52 views
6

想象一下,我想在下面的例子中不斷調用用戶提供的Javascript代碼,就像一個場景,其中getUserResult是,一些用戶(不是我自己)寫一個函數:如何在瀏覽器內安全地運行用戶提供的Javascript代碼?

for (var i = 0; i < N; ++i) { 
    var x = getUserResult(currentState); 
    updateState(currentState, x); 
} 

我如何可以執行瀏覽器和/或Node.js中的代碼類型,沒有任何安全風險?

更一般地,我怎麼能執行一個不允許修改甚至讀取當前的網頁或任何其他全局狀態Javascript函數?有沒有像瀏覽器中的「JS虛擬機」?

JSFiddle如何確保您無法運行任何惡意代碼(至少它可能會欺騙您的登錄名,在頁面的整個生命週期內運行bot,如果不做更糟糕的事情)?或者它不能確保?

+2

聽起來像[Google Caja](https://developers.google.com/caja/)的工作。 –

+0

@GeorgeStocker我用我使用的最終解決方案更新了我的答案。它在瀏覽器中工作,也應該在Node上工作。 – Domi

+0

Node.js的可能的重複[如何運行不受信任的代碼serverside?](http://stackoverflow.com/questions/10937870/how-to-run-untrusted-code-serverside),http://stackoverflow.com/questions/21408343 /如何在瀏覽器中運行javascript-inside-browser-safety-and-safely –

回答

6

在經過多方考慮並在本主題中的其他海報的幫助下(非常感謝您的幫助!),我發現了第一批解答我的問題。儘管我在這裏重寫了我的答案,因爲它總結了這些概念,並且還提供了一些實際的代碼來進行試驗。

一般來說,有兩種解決方案,這一問題:我們既可以使用iframeWorker在隔離的環境中運行代碼,從而使其無法讀取或寫入當前頁面的信息(這是我的第一個重大的安全問題) 。此外,還有沙盒方法,例如Google Caja,但是(默認情況下)也在iframe中運行其代碼。

正如Juan Garcia所提出的那樣,我打算使用web worker API,但這不是完整的故事。儘管工作人員無法直接訪問託管頁面上的任何內容,但仍存在相當多的安全風險。 This site lists all built-ins available in a Worker's context

This JSFiddle演示一種方式來運行的window的環境之外一串代碼,而無需經過服務器,這仍然是不安全的,因爲在評論中指出。

我已經擴展上,並採用黑名單基礎的辦法,採取禁止所有外界溝通了所有的以下內容:

  • Worker
  • WebSocket
  • XMLHttpRequest
  • importScripts

Howeve目前,我正在努力將其移植到白名單方法中,如解釋here所述,以使其在未來的(將來的)附近變得安全。

欲瞭解更多信息,請考慮:

+0

您的當前代碼確實*不*使web worker環境對於任意代碼執行安全鏈接的線程,所以你不應該叫「*安全運行不受信任的代碼*」! – Bergi

+0

「*因此無法讀取或寫入當前頁面的信息(這是我的第一個主要安全問題)*」。不,它不。寫入當前頁面需要DOM訪問權限,是的,因此可以防止網絡釣魚,但是閱讀簡單的XHR就足夠了 - 注意它是從您的域中運行的特權!這是一個巨大的XSS/CSRF漏洞! – Bergi

+0

@Bergi您應該閱讀所有內容:最後,我將介紹安全細節,甚至提供一個完整解決方案的鏈接,以便讓Web工作人員更安全。儘管我會稍微改述一下答案,因爲你說得對,這有點令人困惑。 – Domi

6

可以與工人做到這一點。關於工作者最好的事情是他們在不同的過程中運行,所以如果用戶代碼進入無限循環不會掛起你的頁面。與工作人員的唯一接口是消息接口,因此只能交換字符串,這是非常安全的,但在某些情況下受到限制。

由於並非所有目前使用的瀏覽器都支持工人,iFrame是一種有益的選擇。您可以在JavaScript創建它們,設置顯示爲「無」,將它們添加到文檔中,得到的iframe contentWindow eval函數,然後「破壞」的iframe,如設置outerHTML爲「」(空字符串)。這是棘手的,因爲有時iframe的窗口得到垃圾回收,但如果你能做到正確,你將有一個綁定到一個不同的全局對象,它有一個空文件一個eval。然後,您可以使用全局代碼運行代碼來創建一個接口,其代碼在全局頁面中運行。安全性取決於你如何實現該接口。您不應該公開您的全局對象,這意味着您應該在運行任何用戶代碼之前取消iframe全局中的「父」屬性。你還應該確保你不會從頁面文件傳遞任何元素對象在iframe運行全球的代碼,或者運行代碼的用戶將能夠通過parentElement屬性來瀏覽你的整個文檔,你應該將它們換到例如,您的Element接口使用Object.defineProperty。這是很多工作,它曾經做過,但不確定瀏覽器之間是否兼容。例如,如果我記得,並且我沒有犯任何錯誤,那麼Chrome會讓我在iframe全局中取消父屬性,而在iPad上的Safari中,我無法執行此操作。抱歉,我現在沒有任何代碼與您分享,如果我有時間,我會發布。但是,iframes腳本與頁面運行時相同,這意味着無限循環會將頁面腳本掛起,而今天瀏覽器將代碼編譯爲機器指令可以有效地掛起客戶端操作系統(取決於瀏覽器和OS)。

第三,你可以使用沙盒,在T.J.中有JavaScript自解釋器或類似的東西。 Crowder評論編譯器可以爲你簡化這些,但副作用是運行速度較慢,特別是解釋器。恕我直言,我認爲在ECMA的人應該更好地擔心醜陋的箭頭語法和類似的東西,並實現一個安全的方式運行與不同的全球進程,有一個接口特定的文檔元素及其後代,但無法獲得該元素父級和對文檔的訪問權限。這將有效地啓用一種編寫JavaScript插件的方式並且還保證廣告系統的安全。

+0

我如何在兩者之間進行溝通?我能以某種方式訪問​​從上下文到另一個函數指針嗎? – Domi

+0

在工人使用assyncronous消息接口的情況下。對於iframe上下文,只能使用同步函數調用。口譯員或編譯人員都有自己的界面,因此請檢查文檔。 –

+0

安全性如何?工人是否沒有機會進入窗戶的狀態? – Domi

相關問題