将插件加载到网络应用程序中的安全/可靠方式

问题描述 投票:0回答:3

我有一个接受 JS 插件的网络应用程序。也就是说,其他人编写的 JavaScript 代码,用户想要加载到我的应用程序中。

目前我正在使用 eval() 将他们的 JS 代码评估到运行时,但我知道这不安全。有没有比 eval() 更好的方法来做到这一点?

需要明确的是,用户将我指向一个干燥的文本文件(一个 URL),并且文件中的 JS 需要以某种方式变得生动。

我只知道动态导入 JS 脚本的两种方法:

  1. 使用AJAX,获取JS代码,然后对其运行eval()。
  2. 向 DOM 动态添加
    <script>
    标签

问题的目的是弄清楚一种方法是否比另一种更安全,或者是否有比上述两种选择更好的方法。

javascript web browser google-chrome-extension
3个回答
4
投票

这两者中的一个比另一个更安全吗?

不,从安全角度来看它们同样不好(好)。

它们在细节上有所不同,这会导致采用不同的方法来使它们更安全,但最终两者都会在您的环境中运行由不受信任的第三方编写的代码,并拥有其所有特权。这基本上是一个持续存在的 XSS 问题。

还有比上述2种更好的方法吗?

很多。这主要取决于这些插件应该在您的应用程序中做什么、谁编写它们以及谁安装(启用)它们。作为应用程序提供商和用户,您都不希望任意代码对用户的数据造成严重破坏。如果插件需要访问数据,您需要采取管理措施来确保只有受信任的代码才会运行,例如插件代码审核。至少您需要通知您的用户,他们在启用插件之前必须信任插件作者,这会给他们带来负担。此外,您还应该确保拥有可用日志,以防出现问题。

如果您确实想运行任意、不受信任的代码而不授予其访问用户数据的权限,您将需要考虑沙箱。有多种方法本质上是在代码无法脱离的虚拟机中执行。


4
投票

对于 Chrome 扩展,我会专门使用 sandboxingEval,它允许加载可以在扩展托管的 iframe 中访问的沙盒文件。唯一的消息传递是通过普通的 iframe 消息传递。

例如,在

manifest.json
中声明要沙箱的页面:

{
  ...
  "sandbox": {
    "pages": [
      "plugin.html"
    ]
    "content_security_policy":
        "sandbox allow-scripts; script-src 'self' https://plugin.com/"
  ],
  ...
}

确保外部域已列入白名单,以便可以嵌入。在 CSP 策略中,如果需要嵌入

allow-scripts
,则存在
<scripts>

现在在沙盒页面

plugin.html
中,使用外部脚本执行任何操作。在这种情况下,外部插件被下载,并通过消息传递将消息传递回扩展进程。

<!doctype html>
<html>
  <head>
    <script src="https://plugin.com/mohamedmansour/plugin.js"></script>
  </head>
  <body>
    <script>
      // Whatever my plugin contract is, lets send something back to our extension
      // that the plugin initialized.
      Plugin.do.something.here(() => {
          window.postMessage({
              name: 'CustomInitEvent',
              data: 'initializing'
          }, *);
      });

      // Listen from your extension plugin.html page some events.
      window.addEventListener('message', (event) => {
        var command = event.data.command;

        switch(command) {
          case 'CustomCommandA':
            event.source.postMessage({
              command: 'CustomCommandHello',
              data: 'pong command a'
            }, event.origin);
            break;
        }
      });
    </script>
  </body>
</html>

现在在弹出窗口或任何地方,只需嵌入

plugin.html
。在这种情况下,popup.html 看起来像这样

<html>
  <head>
    <script src="plugin-manager.js"></script>
  </head>
  <body>
    <iframe id="theFrame" src="plugin.html"></iframe>
  </body>
</html>

然后你的

plugin-manager.js
负责控制插件。

const iframe = document.getElementById('theFrame');
window.addEventListener('message', function(event) {
  switch(event.name) {
    case 'CustomInitEvent':
      console.log('Plugin Initialized');
      break;

    case 'CustomCommandHello':
      console.log('Hey!');
      break;
  }
});

iframe.contentWindow.postMessage({
   command: 'CustomCommandA'
});

iframe.contentWindow.postMessage({
   command: 'CustomCommandB'
});

类似的事情。如果需要动态插件,只需将查询参数添加到 iframe 即可。在

plugin.html
内,只需动态添加脚本元素,然后这样调用即可:

<iframe id="theFrame" src="plugin.html?id=121212"></iframe>

0
投票

您可能需要考虑的一个选项是在 WebAssembly 实例中运行插件。这有一些好处:

  1. 它具有许多非常强大的沙箱保证https://web assembly.org/docs/security/并且旨在运行不受信任的代码。
  2. 插件可以使用任何语言,而不仅仅是 javascript,包括更多性能语言,如 rust、go、c、zig 等。您的 javascript 应用程序不需要知道或关心插件是用什么语言编写的在这里创建和运行插件非常快。
  3. 插件也可以在后端运行。您实际上可以在任何地方运行它们,因为现在到处都有 WebAssembly 运行时。

缺点是,争论所有这些低级技术可能有点棘手。这就是我推荐像 Extism 这样的开源项目的地方,以帮助平滑一些较低级别的细节:https://extism.org/

© www.soinside.com 2019 - 2024. All rights reserved.