在沙箱 IFrame 中安全地玩遊戲

Mike West

想在現今的網路環境中打造豐富的體驗,不容忽視 讓您沒有真正的控制權 第三方小工具可以促進參與度,並發揮整體廣告效用 因此,使用者產生的內容有時比以往更重要 而非網站的原生內容絕對不能放棄交易,但可惜 都可能提高網站上某些 BadTM 入侵的風險。每項 每個嵌入的小工具 (每則廣告和社群媒體小工具) 都有 攻擊向量:

內容安全政策 (CSP) 可降低這兩類內容帶來的風險 您可以將特別信任的指令碼和其他來源加入許可清單 內容。這是指向正確方向的重要步驟,但值得注意的是 大多數 CSP 指令的保護是二進位檔案:資源是 否則就不適用有時候「我不會 我確實信任這個內容來源,但真的好酷!嵌入 拜託,但別讓網站損毀。」

最低權限

基本上,我們正在尋找適當的機制,可將內容 只嵌入執行工作所需的最低能力等級如果小工具 不需要彈出新視窗,因此無法取得 window.open 的存取權, 受傷了。如果不需要 Flash,通常關閉外掛程式支援功能就不是 問題。我們已盡可能採取安全措施,只要遵循「最低」原則 權限和封鎖 且每項功能與使用者我們希望的功能 。如此一來,我們不必再盲目信任 嵌入的內容不會利用不應使用的權限這項服務 而是無法在一開始就存取這項功能

iframe 元素是達成此解決方案完善架構的第一步。 在 iframe 中載入某些不受信任的元件,可提供區隔度量 應用程式與要載入的內容之間有何關聯頁框內容 無法存取網頁的 DOM、您儲存在本機的資料或 可繪製到頁面上的任意位置受限於 Pod 的儲存範圍 外框然而,這個區隔並非真正完善。包含的頁面 但還是有許多令人困擾或惡意行為的選項:自動播放 影片、外掛程式和彈出式視窗都是冰山一角

iframe 元素的 sandbox 屬性 所提供的資訊,讓我們能針對影格內容設下更嚴格的限制。我們可以 指示瀏覽器以低權限載入特定頁框的內容 只允許部分必要功能 工作方式

已完成,但驗證

Twitter 的「Tweet」按鈕是很實用的功能範例 安全嵌入網站上Twitter 可讓您將 透過 iframe 傳送按鈕 替換為下列程式碼:

<iframe src="https://platform.twitter.com/widgets/tweet_button.html"
        style="border: 0; width:130px; height:20px;"></iframe>

讓我們一起仔細看看有哪些功能可以排除 載入至頁框中的 HTML 只會執行一小段程式碼 來自 Twitter 伺服器的 JavaScript,並產生填入 點擊時的跳轉介面。該介面需要存取 Twitter 的 Cookie,以便將推文連結至正確帳戶,同時需要 提交 Twitter 訊息表單。就是這麼簡單轉譯影格時 無需瀏覽頂層視窗,即可 其他功能這個應用程式不需要這些權限 首先,我們要透過沙箱內容沙箱 移除這些容器

沙箱功能是以許可清單為基礎運作。首先,您必須移除所有 角色清單,接著將個別功能重啟 套用至沙箱設定的特定標記在 Twitter 小工具中,我們 決定啟用 JavaScript、彈出式視窗、表單提交和 twitter.com 的 Cookie。方法是在 iframe 中加入 sandbox 屬性,並使用 下列值:

<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
    src="https://platform.twitter.com/widgets/tweet_button.html"
    style="border: 0; width:130px; height:20px;"></iframe>

就是這麼簡單!我們提供了所有必要的功能, 會盡快拒絕瀏覽器使用我們未要求的權限 透過 sandbox 屬性的值明確授予該物件。

針對功能進行精細的控制

我們在上述範例中看到幾個可能的沙箱標記 請深入探究屬性的內部運作方式。

如果某個 iframe 含有空白的沙箱屬性,則該框架文件將完全採用沙箱機制,並由 相關限制:

  • 而 JavaScript 不會在頁框中的文件中執行。這不僅包括 透過指令碼標記明確載入的 JavaScript,同時也是內嵌事件處理常式 以及 javascript: 網址這也代表 noscript 標記中包含的內容 會顯示,就像使用者已經停用指令碼一樣。
  • 頁框式文件會載入至不重複的來源中 相同來源的檢查將會失敗。不重複來源與從未出現過其他來源 甚至自行建立除此之外,這意味著文件沒有任何 存取任何來源 Cookie 或任何其他儲存機制中儲存的資料 (DOM 儲存空間、索引資料庫等)。
  • 加上外框的文件無法建立新視窗或對話方塊 (透過 window.opentarget="_blank")。
  • 無法提交表單,
  • 無法載入外掛程式。
  • 頁框中的文件只能瀏覽本身,無法瀏覽頂層父項。 設定 window.top.location 將擲回例外狀況,並按一下 target="_top"不會有任何作用。
  • 自動觸發的功能 (自動聚焦的表單元素、自動播放) 影片等) 遭到封鎖。
  • 無法取得指標鎖定。
  • 框架文件包含的 iframes 會忽略 seamless 屬性。

這是一個相當明顯的草圖,而且一份文件已載入完全沙箱的 iframe 表示風險非常低當然,這麼做也無法帶來許多好處: 您或許可以透過完整的沙箱 移除部分靜態內容 放鬆一下。

除了外掛程式以外,下列每項限制都能解除 在沙箱屬性的值中新增標記。採用沙箱機制的文件永遠 執行外掛程式,因為外掛程式是無沙箱防護的原生程式碼,其他部分則公平公正 遊戲:

  • allow-forms允許提交表單。
  • allow-popups 允許 (衝!) 彈出式視窗。
  • allow-pointer-lock 允許 (驚喜!) 指標鎖定。
  • allow-same-origin 可讓文件維持來源;已載入網頁 「https://example.com/」會保留該來源的資料存取。
  • allow-scripts 允許執行 JavaScript,也能讓功能 觸發的自動轉換 (因為他們很容易透過 JavaScript 導入)。
  • allow-top-navigation 可讓文件從頁框中排除 正在瀏覽頂層視窗

瞭解這些之後,我們就能評估客戶究竟為何 上述 Twitter 範例有一組沙箱標記:

  • allow-scripts 為必要項目,因為載入至頁框的網頁會執行某些程式碼 用於處理使用者互動的 JavaScript。
  • allow-popups 是必要項目,因為按鈕會彈出新的 Twitter 訊息表單 視窗。
  • allow-forms 為必填欄位,因為字幕表單應提交表格。
  • allow-same-origin 為必要欄位,因為 twitter.com 的 Cookie 是 無法存取,且使用者無法登入後才能提交表單。

還有一個重點是,沙箱的旗標同樣會套用至頁框 適用於沙箱中建立的任何視窗或頁框這意味著 新增 allow-forms 至頁框的沙箱中,即使表單已存在 會在頁框彈出的視窗中顯示

設定 sandbox 屬性後,小工具只會取得其權限 以及外掛程式、頂端導覽和指標鎖定等功能 已封鎖。已降低嵌入小工具的風險,但效果不彰。 這對關切的人而言是一大福音。

權限區隔

對第三方內容採用沙箱機制,以便在 低權限環境的確有利於提升不過,您覺得 自己的程式碼?你相信自己,對吧?所以會擔心沙盒作業嗎?

我會再詢問這個問題:如果您的程式碼不需要外掛程式,為何請 該如何存取外掛程式?最好是不會有人使用, 進而入侵您的企業每個人的程式碼都有 而且幾乎每個應用程式都容易受到利用 或其他不同如果打造自己的程式碼,即使攻擊者成功地 會無法完整存取 應用程式來源他們就只能執行應用程式 可執行的作業 信任關係還是差不多,但不是那麼壞。

您可以將應用程式分割到 然後為每一塊架設最低限度的沙箱機制。 這項技巧在原生程式碼中相當常見,例如 Chrome 會自行斷開 轉換為高權限瀏覽器程序,並且能存取本機硬碟 且可建立網路連線,以及許多低權限轉譯器程序 不必費心剖析不受信任的內容轉譯器不需要觸控 瀏覽器會負責提供所有必要資訊 轉譯網頁。即使出乎巧妙的駭客設法毀損轉譯器, 它的功能沒那麼大,因為轉譯器本身無法做到這一點: 所有高權限存取權都必須透過瀏覽器程序轉送。 攻擊者需要在系統的不同片段中找到幾個小孔 造成任何損害,大幅降低成功產出的風險。

採用安全沙箱機制 eval()

採用沙箱機制 postMessage API、 要應用在網路上就很容易出錯第 塊 您的應用程式可能會在沙箱防護的 iframe 中運作,而父項文件可以 藉由張貼訊息和監聽 回應。這種結構可確保利用 能將傷害降到最低還能強迫您 才能清楚確立需要的整合點 請務必仔細確認輸入和輸出內容我們來看一個玩具範例 看看該有用

Evalbox 是一款令人期待的應用程式 ,然後評估為 JavaScript。哇,對吧?恰到好處 這幾年來,我們一直在等待這很危險 當然,就像允許執行任意 JavaScript 時, 來源提供的所有資料也都可供擷取我們會降低 確定程式碼是在沙箱中執行時,就會發生 Bad ThingsTM 現象 因此安全性相當高我們會逐步完成 從框架內容開始:

<!-- frame.html -->
<!DOCTYPE html>
<html>
    <head>
    <title>Evalbox's Frame</title>
    <script>
        window.addEventListener('message', function (e) {
        var mainWindow = e.source;
        var result = '';
        try {
            result = eval(e.data);
        } catch (e) {
            result = 'eval() threw an exception.';
        }
        mainWindow.postMessage(result, event.origin);
        });
    </script>
    </head>
</html>

想檢視訊息,我們整理了一份簡短的文件, 叫用 window 物件的 message 事件,這樣就能從父項提取其他物件。 每當父項執行 iframe 內容上的 postMessage 時,這個事件 觸發,因此父項會允許我們存取該字串 此程序的第一步 是將程式碼簽入執行所有單元

在處理常式中,我們擷取事件的 source 屬性,也就是父項 視窗。我們會在課程開始後,將後續努力的結果傳送給我們 完成。接著,我們會將現有資料傳送至 eval()。這個呼叫已納入 try 區塊,屬於禁用作業 沙箱中的 iframe 內經常產生 DOM 例外狀況我們會抓到 改為回報友善的錯誤訊息最後,我們會發布 返回上層視窗這個部分相當簡單明瞭。

父項做法很複雜我們會使用 textarea 建立極小的 UI 和執行中的 button,我們會透過 frame.html 採用沙箱機制的 iframe,僅允許執行指令碼:

<textarea id='code'></textarea>
<button id='safe'>eval() in a sandboxed frame.</button>
<iframe sandbox='allow-scripts'
        id='sandboxed'
        src='frame.html'></iframe>

現在我們將把東西接起來來進行執行。首先,我們會監聽 iframealert()。可說是實際應用 會減少干擾:

window.addEventListener('message',
    function (e) {
        // Sandboxed iframes which lack the 'allow-same-origin'
        // header have "null" rather than a valid origin. This means you still
        // have to be careful about accepting data via the messaging API you
        // create. Check that source, and validate those inputs!
        var frame = document.getElementById('sandboxed');
        if (e.origin === "null" &amp;&amp; e.source === frame.contentWindow)
        alert('Result: ' + e.data);
    });

接著,我們會連結事件處理常式以點選 button。當使用者 我們會擷取 textarea 目前的內容,並將這些內容傳遞至 待執行的影格:

function evaluate() {
    var frame = document.getElementById('sandboxed');
    var code = document.getElementById('code').value;
    // Note that we're sending the message to "*", rather than some specific
    // origin. Sandboxed iframes which lack the 'allow-same-origin' header
    // don't have an origin which you can target: you'll have to send to any
    // origin, which might alow some esoteric attacks. Validate your output!
    frame.contentWindow.postMessage(code, '*');
}

document.getElementById('safe').addEventListener('click', evaluate);

就是這麼簡單!我們建立了非常簡單的評估 API 評估中的程式碼無法存取 Cookie 等機密資訊 或 DOM 儲存空間同樣地,評估的程式碼也無法載入外掛程式、彈出新視窗 或任何其他擾人或惡意活動

您也可以將單體式應用程式拆分為 單一用途元件每一個容器都可納入簡單的訊息 API 中, 這很像之前寫的一樣高權限的上層視窗可做為 能將訊息傳送至每個 以最低權限執行工作、監聽結果 確認每個模組僅提供所需資訊。

但請注意,處理頁框內容時必須謹慎 與父項資源相同的來源如果 https://example.com/ 使用沙箱機制,針對同一來源顯示另一個網頁 包含 allow-same-originallow-scripts 標記,則 頁框式網頁可到達上層網頁,並移除沙箱屬性 。

在沙箱中玩遊戲

現在,許多瀏覽器都支援沙箱,包括 Firefox 17 以上版本、 在寫作前,Chrome 搭載了最新版 IE10 以上版本, 支援表)。套用 sandbox 屬性加入 iframes,讓 存取的內容,「只」「只」」取得 內容以正常運作讓您有機會降低 涉及到第三方內容,以及不只是什麼 內容安全性解決方案, 政策

此外,沙盒是降低巧妙風險的一種強大技術 攻擊者將能運用你自有程式碼的漏洞。建立方法是以 將單體式應用程式加進一組沙箱化服務中 攻擊者就會被迫不及待 只入侵特定影格同時保有控制器這是 執行起來更加困難,尤其是因為控制器可以大幅降低 涵蓋範圍您可以使用安全性相關措施來稽核「該」程式碼: 或是向瀏覽器尋求協助

但沙箱並不是所有作業流程 網路安全它提供縱深防禦 控管使用者部分用戶端,還無法完全仰賴瀏覽器支援 (如果貴機構能控管使用者 例如企業環境、 例如「hooray!」)。未來會來... 但現在沙箱是另一層 但這並不是完全的防禦機制 確保安全無虞儘管如此,圖層還是非常棒。建議您利用這種方法 第一。

其他資訊

  • HTML5 應用程式中的權限區隔」 是一篇有趣的論文,探討如何設計出一個小型架構 並應用在三個既有的 HTML5 應用程式上

  • 沙箱搭配另外兩個新的 iframe 使用時更有彈性 屬性:srcdoc、 和 seamless。 前者可讓您在頁框中填入內容,而無須額外負擔 HTTP 要求,而後者可讓樣式傳入頁框內容。 目前兩者的瀏覽器支援都不太正常 (Chrome 和 WebKit) 夜間睡床)。但未來是值得注意的組合建議做法 舉例來說,系統會使用下列程式碼,對文章進行沙箱註解:

        <iframe sandbox seamless
                srcdoc="<p>This is a user's comment!
                           It can't execute script!
                           Hooray for safety!</p>"></iframe>