谷歌浏览器扩展程序内容安全策略

3
我是一个有用的助手,可以为您翻译文本。
我正在开发一个谷歌浏览器扩展程序,需要包含Facebook的sdk.js文件。但问题在于,由于内容安全策略,我无法使应用程序正常工作。以下是我的部分代码:
manifest.json
{
  "manifest_version": 2,

  "name": "<app-name>",
  "description": "<description>",
  "version": "0.1",

  "permissions": [
  "tabs","<all_urls>"
  ],
  "content_scripts": [
  {
    "matches": [
    "http://*/*",
    "https://*/*"
    ],
    "js": ["intercept_connections.js"]
  }
  ],
  "content_security_policy": "script-src 'self' https://connect.facebook.net/en_US/ 'unsafe-eval'; object-src 'self'",
  "background": {
    "scripts" : ["background.js"]
    },
    "browser_action": {
      "default_icon": "icon.png",
      "default_popup": "popup.html"
    }
  }

popup.html

<html>
<head>
    <title>Facebook Mass Sharer</title>


    <script type="text/javascript" src="popup.js"></script>
    <script type="text/javascript" src="FbApi.js"></script>
</head>

<body>
<body>
    <h1>Post to Facebook</h1>
    <button id="postTest">TestMe</button>

  </body>
</body>
</html>

popup.js

var handleClick = function() {
    postToGroup(<groupID>);
}

var initialize = function() {
    var test = document.getElementById('postTest');
    test.addEventListener("click",handleClick);
}

window.addEventListener("load", initialize);

FbApi.js(由我制作)


window.onload = function() {
    window.fbAsyncInit = function() {
        FB.init({
          appId      : '<appID>',
          xfbml      : true,
          version    : 'v2.1',
          oauth      : true
        });
      };

      (function(d, s, id){
         var js, fjs = d.getElementsByTagName(s)[0];
         if (d.getElementById(id)) {return;}
         js = d.createElement(s); js.id = id;
         js.src = "https://connect.facebook.net/en_US/sdk.js";
         fjs.parentNode.insertBefore(js, fjs);
       }(document, 'script', 'facebook-jssdk'));
}

var postToGroup = function(groupID) {
    FB.api(
    "/"+groupID+"/feed",
    "POST",
    {
        "message": "This is a test message"
    },
    function (response) {
      if (response && !response.error) {
        /* handle the result */
      }
    }
);
}

事情是我一直在得到这个错误:
Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "script-src https:// 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

我尝试将"content_security_policy": "script-src 'self' https://connect.facebook.net/en_US/ 'unsafe-eval'; object-src 'self'"更改为"content_security_policy": "script-src 'self'; object-src 'self'""content_security_policy": "script-src 'self' https://connect.facebook.net/en_US/ 'inline-eval'; object-src 'self'",如错误提示所建议的,但没有成功。我该尝试什么?


你能看到是什么导致了这个错误吗?听起来像是Facebook在某个地方使用了eval。 - jamesmortensen
在 Facebook API 中,有一种使用 eval 的方法...请看这里:[https://connect.facebook.net/en_US/sdk.js] 只需搜索 eval,您就会发现它只出现了一次。但是我正在使用 'unsafe-eval',所以我不知道我的错误在哪里。 - Daniel Bejan
我非常确定Google认为eval在任何地方都不安全。我认为你不能覆盖它。你需要做的是使用iframe来加载内容,这样它就无法访问任何Chrome API。然后你需要使用postMessage在iframe和扩展程序的主体之间进行通信。 - jamesmortensen
错误是违反了 unsafe-inline 而不是 unsafe-eval - abraham
是的,但如果我取消 unsafe-inline 并删除 unsafe-eval,我会收到有关违反 unsafe-eval 的错误。 - Daniel Bejan
我也卡在这里了。你最终解决了如何消除那个错误吗?另外,我一直收到“域未包含在您的应用程序中”的错误?你知道有什么解决方法吗? - CodeSsscala
1个回答

2
Google认为eval是一种不安全的、潜在危险的操作,因为动态内容可能会进入应用程序/扩展,并运行自身,从而获得访问文件系统和其他通常对普通网站JavaScript禁止的资源的强大chrome.* API的整个世界。
因此,在您的扩展和应用程序中使用这些违反CSP的库的唯一方法是将它们沙盒化
我们通过将扩展包内的特定HTML文件列为沙盒化来实现这一点。每当加载一个沙盒化页面时,它将被移动到一个唯一的源,并被拒绝访问chrome.* API。如果我们通过iframe将这个沙盒化页面加载到我们的扩展中,我们可以传递消息,让它以某种方式执行这些消息,并等待它将结果传回给我们。这个简单的消息机制为我们提供了在扩展工作流程中安全地包含eval驱动代码所需的一切。
简而言之,您需要在扩展中创建一个额外的组件,即一个HTML文件,您可以对其进行沙盒处理,并加载Facebook代码。然后,在沙盒页面中添加监听器,以接收来自包含HTML页面的消息,然后在扩展中处理事件。这样可以保护您的用户免受eval的影响,因为eval的代码无法访问沙盒中的任何Chrome API。
当我使用sipml5的JavaScript SIP库工作时,我也遇到了同样的问题。该库相当慷慨地使用了eval,因此使用该库的唯一方法是在沙盒中。我创建了一个用于处理在沙盒和主应用程序之间同步存储数据的小型库,称为Sandbox StorageAPI for Chrome™。在代码中,您可以看到我如何在沙盒和主页面之间进行通信。

manifest.json:

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

mainpage.html:

<!-- Sandboxed page -->
    <iframe height="800" width="1200" id="sandboxFrame" class="sandbox active" src="sandbox.html" style=""></iframe>

storageAPI.js:

在这里,我在沙盒中创建了一个监听器,用于监听应用/扩展的主要安全部分向沙盒“注册”自己,然后存储该引用,以便沙盒可以与主模块进行通信:
window.addEventListener('message', function(event) {
            console.info("Message received from wrapper = " + JSON.stringify(event.data));
            console.info("location = " + window.location.href);
            switch(event.data.command) {

                case 'initStorageAPI':
                    storageAPI.storage = event.data.storage;  result = "It's alive!!!";
                    storageAPI.sandbox.window.onload();
                    console.info("Prepare to postMessage back to the wrapper...");
                    storageAPI.wrapper = event;
                    event.source.postMessage({'command':'initStorageComplete','result': result}, event.origin);

这里有一个例子,我们将数据发送回主模块:
storageAPI.setItem = function(key, value) {
        if(storageAPI.CHROME_EXTENSION == false) {
            return window.localStorage.setItem(key, value);
        } else {
            storageAPI.storage[key] = value;
            // send back to the wrapper to store
            storageAPI.wrapper.source.postMessage({'command':'writeStorage', 'storage': storageAPI.storage}, storageAPI.wrapper.origin);

        }

    };

总之,您可以使用类似的技术将数据从沙盒传递到主模块并返回,将不安全的库与扩展的安全敏感部分连接起来。请参阅文档以获取更多详细信息。
请记住,iframe甚至可以被隐藏。您只需要它能够运行不安全的代码即可。
免责声明:我是Chrome™开发者的沙盒StorageAPI。我与Google或Chrome无关,所有商标均属于Google。

1
CSP strict-dynamic对Chrome扩展程序无效的任何想法吗? - Pacerier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接