我正在开发的 Google Chrome 扩展程序不断抛出 CSP 错误

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

我正在创建一个仅供个人使用的 Chrome 扩展程序。我需要它来监视对 https://www.instagram.com/api/graphql 发出的任何请求并记录响应(即将其转发到另一个执行此操作的脚本)。我对 Chrome 扩展程序开发非常陌生,所以请原谅我任何菜鸟错误。

目前看来我能够获取响应; console.log 还打印出响应良好。但是,我陷入了 CSP 错误(内容安全策略),并且它不会将收集到的响应转发到我的脚本(当前位于本地主机上)。

到目前为止,我所拥有的都是来自各地的复制粘贴内容的混合物,但我明白它的作用。我只是不明白我必须做什么才能让它做我想做的事情😊😊:

manifest.json

{

    "manifest_version": 3,
    "name": "BytE IG",
    "description": "BytE Instagram checker",
    "version": "1.3",
    "content_security_policy": {
        "extension_pages": "script-src 'self' http://localhost; object-src 'self' script-src-elem 'self'"
    },

    "background": {
        "service_worker": "background.js"
    },

    "host_permissions": [
        "*://*/*"
    ],

    "permissions": [
        "activeTab",
        "tabs",
        "webRequest"
    ],

    "content_scripts": [
        {
            "matches": ["*://*.instagram.com/direct/*"],
            "run_at": "document_start",
            "js": ["inject.js"]
        }
    ],

    "web_accessible_resources": [
        {
            "resources": ["injected.js"],
            "matches": ["*://*.instagram.com/*"]
        }
    ]

}

背景.js

chrome.webRequest.onCompleted.addListener(
    (details) => {
      const url = new URL(details.url);

      console.log('caught request' + url);
    },
    {
      urls: "https://*.instagram.com/api/graphql*"
    }
);

注入.js

var s = document.createElement('script');
s.src = chrome.runtime.getURL('injected.js');
s.onload = function() {
    this.remove();
};
(document.head || document.documentElement).appendChild(s);

注入.js

(function(xhr) {

    var XHR = XMLHttpRequest.prototype;

    var open = XHR.open;
    var send = XHR.send;
    var setRequestHeader = XHR.setRequestHeader;

    XHR.open = function(method, url) {
        this._method = method;
        this._url = url;
        this._requestHeaders = {};
        this._startTime = (new Date()).toISOString();

        return open.apply(this, arguments);
    };

    XHR.setRequestHeader = function(header, value) {
        this._requestHeaders[header] = value;
        return setRequestHeader.apply(this, arguments);
    };

    XHR.send = function(postData) {

        this.addEventListener('load', function() {
            var endTime = (new Date()).toISOString();

            var myUrl = this._url ? this._url.toLowerCase() : this._url;
            if(myUrl) {

                if (postData) {
                    if (typeof postData === 'string') {
                        try {
                            // here you get the REQUEST HEADERS, in JSON format, so you can also use JSON.parse
                            this._requestHeaders = postData;    
                        } catch(err) {
                            console.log('Request Header JSON decode failed, transfer_encoding field could be base64');
                            console.log(err);
                        }
                    } else if (typeof postData === 'object' || typeof postData === 'array' || typeof postData === 'number' || typeof postData === 'boolean') {
                            // do something if you need
                    }
                }

                // here you get the RESPONSE HEADERS
                var responseHeaders = this.getAllResponseHeaders();

                if ( this.responseType != 'blob' && this.responseText) {
                    // responseText is string or null
                    try {

                        // here you get RESPONSE TEXT (BODY), in JSON format, so you can use JSON.parse
                        var arr = this.responseText;

                        // printing url, request headers, response headers, response body, to console

                        // building your form values
                        var data = new URLSearchParams();
                        data.set('ig', arr);

                        // send to the endpoint
                        fetch("http://localhost:1608/ig.php", {
                            method: 'POST',
                            mode: 'no-cors',
                            cache: 'no-cache',
                            headers: {
                                'Content-Type': 'application/x-www-form-urlencoded',
                            },
                            body: data
                        }).then(function(response) {
                            // check the response object for result
                            // ...
                        });

                    } catch(err) {
                        console.log("Error in responseType try catch");
                        console.log(err);
                    }
                }

            }
        });

        return send.apply(this, arguments);
    };

})(XMLHttpRequest);

我没有得到一个漂亮的小 JSON 到 ig.php,而是得到:

injected.js:62 拒绝连接到“http://localhost:1608/ig.php”,因为它违反了文档的内容安全策略。 (匿名)@injected.js:62 Injected.js:62 拒绝连接到“http://localhost:1608/ig.php”,因为它违反了文档的内容安全策略。 (匿名)@injected.js:62 Injected.js:62 拒绝连接到“http://localhost:1608/ig.php”,因为它违反了文档的内容安全策略。 (匿名)@injected.js:62 Injected.js:62 拒绝连接到“http://localhost:1608/ig.php”,因为它违反了文档的内容安全策略。 (匿名)@injected.js:62 Injected.js:62 拒绝连接到“http://localhost:1608/ig.php”,因为它违反了文档的内容安全策略。

编辑:

我还尝试使用 FQDN 而不是 localhost,并使用 SSL 证书。没有运气。

google-chrome-extension content-security-policy chrome-extension-manifest-v3
1个回答
0
投票

我把这件事搁置了一段时间,然后又回来了。感谢 wOxxOm 的评论 我设法使其可用,并将其转换为 v3。

这超出了我的专业领域(系统管理、DevOps),所以它肯定有很多缺陷,但我只需要它在我的机器上工作。它可能拥有不需要的权限,但这只是我需要尽快进行的快速集成。

这是最终起作用的新代码:

manifest.json:

    {
        "manifest_version": 3,
        "name": "BytE IG",
        "description": "BytE Instagram checker",
        "version": "2.0",
        "background": {
            "service_worker": "background.js"
        },
        "host_permissions": [
            "*://*/*"
        ],
        "permissions": [
            "activeTab",
            "tabs",
            "webRequest"
        ],
    
        "externally_connectable": {
            "matches": [
                "*://*.instagram.com/*"
            ]
        },
          
        "content_scripts": [
            {
                "matches": [
                    "*://*.instagram.com/direct/*"
                ],
                "run_at": "document_start",
                "js": [
                    "inject.js"
                ]
            }
        ],
        "web_accessible_resources": [
            {
                "resources": ["injected.js"],
                "matches": ["*://*.instagram.com/*"]
            }
        ]
    }

注入.js

var s = document.createElement('script');
s.src = chrome.runtime.getURL('injected.js');
s.onload = function() {
    this.remove();
};
(document.head || document.documentElement).appendChild(s);json

注入.js

    (function (xhr) {
    
        var XHR = XMLHttpRequest.prototype;
    
        var open = XHR.open;
        var send = XHR.send;
        var setRequestHeader = XHR.setRequestHeader;
    
        XHR.open = function (method, url) {
            this._method = method;
            this._url = url;
            this._requestHeaders = {};
            return open.apply(this, arguments);
        };
    
        XHR.setRequestHeader = function (header, value) {
            this._requestHeaders[header] = value;
            return setRequestHeader.apply(this, arguments);
        };
    
        XHR.send = function (postData) {
    
            this.addEventListener('load', function () {
                var extensionId = "your-extension-id";
    
                var myUrl = this._url ? this._url.toLowerCase() : this._url;
                if (myUrl) {
    
                    if (postData) {
                        if (typeof postData === 'string') {
                            try {
                                this._requestHeaders = postData;
                            } catch (err) {
                                console.log(err);
                            }
                        }
                    }
    
                    var responseHeaders = this.getAllResponseHeaders();
    
                    if (this.responseType != 'blob' && this.responseText) {
                        // responseText is string or null
                        try {
                            var arr = this.responseText;
                            chrome.runtime.sendMessage(extensionId, {arr: arr});
                        } catch (err) {
                            console.log(err);
                        }
                    }
    
                }
            });
    
            return send.apply(this, arguments);
        };
    
    })(XMLHttpRequest);

background.js(服务工作者)

chrome.runtime.onMessageExternal.addListener(
  function (request, sender, sendResponse) {
    const url = new URL(sender.url);

    console.log('caught request' + url);
    var data = new URLSearchParams();
    data.set('ig', request.arr);

    // send to the endpoint
    fetch("http://localhost:1609/ig.php", {
      method: 'POST',
      mode: 'no-cors',
      cache: 'no-cache',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: data
    }).then(function (response) {
      // check the response object for result
      // ...
    });
  });

inject.js ... 将 ... injected.js 注入到页面上。但是,使用 CSP,您无法直接与网站交互,除非网站所有者批准的网站。我试图绕过这个问题,因为我只需要它在我的浏览器上工作,但没有运气。

但是,您可以从批准的网站向您自己的分机发送消息,然后网站可以将它们发送到需要的地方。

很好。 :)

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