在 Chrome 擴充功能中使用 eval

Chrome 擴充功能系統會強制執行相當嚴格的預設內容安全政策 (CSP)。 政策限制非常簡單明瞭:指令碼必須從線上移至獨立項目 JavaScript 檔案、內嵌事件處理常式必須轉換為 addEventListener,而 eval() 為 已停用。Chrome 應用程式有更嚴格的政策,我們很滿意這項原則 政策內容

但我們知道,各種程式庫都會使用 eval() 和類似 eval 的結構,例如 new Function(),實現效能最佳化並輕鬆表達想法。範本程式庫是 特別容易採用這種實作方式雖然部分 (例如 Angular.js) 支援 CSP 目前許多熱門架構尚未更新為相容的機制 擴充功能勇闖 eval 的世界。因此,移除對該功能的支援已證實更多 問題。

本文件介紹採用沙箱機制,方便你在專案中加入這些程式庫 而不會犧牲安全性為求簡潔,以下我們將說明「擴充內容」一詞,但 概念同樣適用於應用程式

為什麼要採用沙箱機制?

eval 對擴充功能內不安全,因為執行的程式碼能夠存取 排除擴充功能的高權限環境您可以運用多種功能強大的 chrome.* API 嚴重影響使用者的安全性和隱私權。我們最擔心的事就是竊取資料。 優惠解決方案是沙箱,可讓 eval 在不存取 擴充功能的資料或擴充功能的高價值 API。沒有資料、API 也不成問題。

為此,我們會在擴充功能套件中列出特定 HTML 檔案做為沙箱的機制。 沙箱每次載入的網頁都會移至專屬來源,並遭拒 存取 chrome.* API。如果我們透過 iframe 將這個沙箱網頁載入擴充功能 等系統處理訊息後 結果。這個簡單的訊息機制讓我們能安全納入以 eval 為主的所有功能 將程式碼寫入擴充功能工作流程中

建立及使用沙箱。

若要直接參閱程式碼,請取得沙箱擴充功能範例, 關閉。這是建構在控制列之上的小型訊息 API 實際範例 現在應該能取得所有範本資料,方便您踏出第一步。如果您曾 讓我們一起看看這個範例

在資訊清單中列出檔案

凡是應該在沙箱中執行的檔案,都必須在擴充功能資訊清單中列出 sandbox 屬性。這個步驟非常重要,很容易忘記,因此請仔細檢查 資訊清單中會列出沙箱檔案。在本範例中,我們要巧妙地為檔案採用沙箱機制 「sandbox.html」資訊清單項目如下所示:

{
  ...,
  "sandbox": {
     "pages": ["sandbox.html"]
  },
  ...
}

載入沙箱檔案

為了對沙箱檔案進行有趣的操作,我們需要在 都能透過擴充功能的程式碼進行處理這個例子中的 sandbox.html 已載入 透過 iframe 的擴充功能事件頁面 (eventpage.html)。eventpage.js 包含程式碼 這個 API 會在使用者按一下瀏覽器動作 (方法是找出 iframe) 時,將訊息傳送至沙箱 並在其 contentWindow 執行 postMessage 方法。訊息是物件 其中包含兩項屬性:contextcommand。我們稍後會深入探討。

chrome.browserAction.onClicked.addListener(function() {
 var iframe = document.getElementById('theFrame');
 var message = {
   command: 'render',
   context: {thing: 'world'}
 };
 iframe.contentWindow.postMessage(message, '*');
});
如需 postMessage API 的一般資訊,請參閱 MDN 的 postMessage 說明文件 。非常完整且值得一讀請特別注意,資料必須可序列化,才能來回傳遞。例如函式則不同。

執行危險活動

載入 sandbox.html 時,系統會載入處理常式程式庫,並建立並編譯內嵌項目 。

<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>Hello, !</h1>
  </div>
</script>
<script>
  var templates = [];
  var source = document.getElementById('hello-world-template').innerHTML;
  templates['hello'] = Handlebars.compile(source);
</script>

這項操作不會失敗!雖然 Handlebars.compile 最終使用 new Function,但一切正常 與預期完全相同,最後在 templates['hello'] 中取得編譯的範本。

傳回結果

我們將設定訊息監聽器接受指令,讓這個範本可供使用 。我們會使用傳入的 command,決定應採取什麼行動 (您可以 可想而知,不只是進行算繪考慮建立範本?或許透過 context),並直接傳遞至範本以便算繪。轉譯後的 HTML 將傳回至事件網頁,讓擴充功能之後能執行以下動作:

<script>
  window.addEventListener('message', function(event) {
    var command = event.data.command;
    var name = event.data.name || 'hello';
    switch(command) {
      case 'render':
        event.source.postMessage({
          name: name,
          html: templates[name](event.data.context)
        }, event.origin);
        break;

      // case 'somethingElse':
      //   ...
    }
  });
</script>

回到活動網頁,Google 會收到這則訊息,並對 html 進行一些有趣的操作 我們傳遞許多資訊在此情況下,我們會只透過桌面通知回應該通知,但 可以在擴充功能的使用者介面中安全地使用此 HTML。插入方式: innerHTML 不會帶來重大安全性風險,即使是沙箱模式完全破壞也一樣 一旦受到一些巧妙的攻擊,就無法將危險的指令碼或外掛程式內容 進階權限的擴充功能背景資訊

這種機制讓建立範本的程序簡單明瞭,但當然,這不是範本作業的限制。不限 如果程式碼無法在嚴格內容安全政策的方塊中執行,就可能會採用沙箱機制。英吋 事實上,對於「必須能正確執行」的擴充功能的沙箱元件,這項做法通常相當實用 限制您程式的各個部分僅執行最低限度的權限 以便正確執行參閱 Google 的撰寫安全網頁應用程式和 Chrome 擴充功能簡報 2012 年 I/O 大會介紹了這種技巧的實際應用範例,在您的 讓應用程式從可以最快做出回應的位置 回應使用者要求