在 Chrome 扩展程序中使用 eval

Chrome 的扩展程序系统会强制执行相当严格的默认内容安全政策 (CSP)。 政策限制很简单:脚本必须脱机移至单独的 JavaScript 文件,必须转换内嵌事件处理脚本才能使用 addEventListener,而 eval() 已停用。Chrome 应用有更严格的政策,我们对安全性非常满意 政策所提供的属性。

不过,我们知道还有各种库都使用类似 eval()eval 的结构,例如 new Function(),用于优化性能和易于表达。模板库 尤其容易采用这种实施方式。虽然某些环境(如 Angular.js)支持 CSP out 许多热门框架尚未更新为与 Android Studio 兼容的 扩展程序的少了 eval 的世界。因此,事实证明,取消对该功能的支持 或性能超出预期的问题

本文档介绍沙盒是一种可在您的项目中添加这些库的安全机制 同时又不影响安全性为简洁起见,我们将全程使用附加信息一词,但 这一概念同样适用于应用。

为何要使用沙盒?

eval 在扩展程序中很危险,因为它执行的代码可以访问 扩展程序的高权限环境提供了大量功能强大的 chrome.* API, 严重影响用户的安全和隐私;我们最担心的是简单的数据渗漏问题。 提供的解决方案是一个沙盒,在此沙盒中,eval 无需访问 或扩展程序的高价值 API。没有数据、不使用 API,也没有关系。

为此,我们会将扩展程序软件包内的特定 HTML 文件列为已沙盒化。 每当有沙盒机制加载网页时,系统都会将其移动到唯一来源,并会被拒绝 对 chrome.* API 的访问权限。如果通过 iframe 将此沙盒化页面加载到扩展程序中, 然后向其传递消息,让其以某种方式处理这些消息,然后等待它为我们传回 结果。这种简单的消息传递机制为我们提供了安全纳入由 eval 驱动的一切所需的一切 代码生成。

创建和使用沙盒。

如果您希望直接查看代码,请下载沙盒示例扩展程序 关闭。这是一个基于 Handlebars 构建的小型消息传递 API 的有效示例 模板库,它应该会为您提供开始操作所需的一切。为了 在这里,我们一起来看看这个示例。

列出清单中的文件

应该在沙盒中运行的每个文件都必须在扩展程序清单中列出,方法是添加 sandbox 属性。这是非常重要的一步,很容易被忘记,因此请仔细检查 您的沙盒文件会在清单中列出在此示例中,我们巧妙地对文件进行沙盒化 名为“sandbox.html”清单条目如下所示:

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

加载沙盒文件

为了对沙盒化文件执行一些有趣的操作,我们需要在 可以通过该扩展程序的代码进行处理在此示例中,sandbox.html已加载到 扩展程序的活动页 (eventpage.html) 通过 iframe.eventpage.js 包含代码 该函数通过查找 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 后,它会加载 Handlebars 库,创建并编译内嵌的 这就像 Handlebars 建议那样:

<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>

返回到“活动”页面,我们会收到此消息,并使用 html 执行一些有趣的操作 传递的数据。在此示例中,我们仅通过桌面通知发出语音提示 完全可以放心地将此 HTML 用作扩展程序界面的一部分。通过以下方式插入: innerHTML 不会造成明显的安全风险,即使沙盒遭到完全入侵, 就无法将危险的脚本或插件内容注入到 高权限扩展程序上下文

这种机制使模板化变得简单直接,但当然不限于模板化。不限 在严格内容安全政策下无法正常运行的代码可以被沙盒化;在 实际上,对那些能够正常运行的扩展程序组件进行沙盒化往往很有帮助, 将程序的各部分限制在运行所需的最小权限集内, 正确执行。Google 的编写安全的 Web 应用和 Chrome 扩展程序演示文稿 2012 年 Google I/O 大会提供了这些技术的实际应用示例,值得您花 56 分钟的时间 。