23

我正在开发一个 Chrome 扩展程序,它可以从某些网站向我控制的 API 发出请求。在 Chrome 73 之前,该扩展程序可以正常工作。升级到 Chrome 73 后,我开始收到以下错误:

跨源读取阻止 (CORB) 阻止 了具有 MIME 类型 application/json 的跨源响应http://localhost:3000/api/users/1

根据Chrome 关于 CORB 的文档,如果满足以下所有条件,CORB 将阻止请求的响应:

  1. 该资源是“数据资源”。具体来说,内容类型为 HTML、XML、JSON

  2. 服务器以X-Content-Type-Options: nosniff标头响应,或者如果省略此标头,Chrome 通过检查文件检测到内容类型是 HTML、XML 或 JSON 之一

  3. CORS 没有明确允许访问资源

此外,根据“Spectre and Meltdown 的教训”(Google I/O 2018)mode: cors ,添加到调用中似乎很重要fetch,即fetch(url, { mode: 'cors' }).

为了解决这个问题,我做了以下更改:

首先,我将以下标头添加到我的 API 的所有响应中:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Origin: https://www.example.com

其次,我更新了fetch()对扩展的调用,如下所示:

fetch(url, { credentials: 'include', mode: 'cors' })

然而,这些改变并没有奏效。我可以更改什么以使我的请求不会被 CORB 阻止?

4

3 回答 3

19

基于“更改 Chrome 扩展内容脚本中的跨域请求”中的示例,我将所有调用替换为具有类似 APIfetch的新方法fetchResource,但将fetch调用委托给后台页面:

// contentScript.js
function fetchResource(input, init) {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({input, init}, messageResponse => {
      const [response, error] = messageResponse;
      if (response === null) {
        reject(error);
      } else {
        // Use undefined on a 204 - No Content
        const body = response.body ? new Blob([response.body]) : undefined;
        resolve(new Response(body, {
          status: response.status,
          statusText: response.statusText,
        }));
      }
    });
  });
}

// background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  fetch(request.input, request.init).then(function(response) {
    return response.text().then(function(text) {
      sendResponse([{
        body: text,
        status: response.status,
        statusText: response.statusText,
      }, null]);
    });
  }, function(error) {
    sendResponse([null, error]);
  });
  return true;
});

这是我能够对解决问题的应用程序进行的最小更改。(注意,扩展和后台页面之间只能传递 JSON-serializable 对象,所以我们不能简单地将 Fetch API Response 对象从后台页面传递给扩展。)

后台页面不受 CORS 或 CORB 的影响,因此浏览器不再阻止来自 API 的响应。

于 2019-03-18T06:46:57.490 回答
6

https://www.chromium.org/Home/chromium-security/extension-content-script-fetches

为了提高安全性,自 Chrome 85 起,Chrome 扩展程序不允许从内容脚本进行跨域提取。此类请求可以从扩展程序后台脚本发出,并在需要时中继到内容脚本。

您可以这样做以避免跨域。

旧内容脚本,进行跨域提取:

var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
         encodeURIComponent(request.itemId);
fetch(url)
  .then(response => response.text())
  .then(text => parsePrice(text))
  .then(price => ...)
  .catch(error => ...)

新的内容脚本,要求其后台页面获取数据:

chrome.runtime.sendMessage(
    {contentScriptQuery: "queryPrice", itemId: 12345},
    price => ...);

新的扩展背景页面,从已知 URL 获取并中继数据:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.contentScriptQuery == "queryPrice") {
      var url = "https://another-site.com/price-query?itemId=" +
              encodeURIComponent(request.itemId);
      fetch(url)
          .then(response => response.text())
          .then(text => parsePrice(text))
          .then(price => sendResponse(price))
          .catch(error => ...)
      return true;  // Will respond asynchronously.
    }
  });

允许manifest.json中的 URL (更多信息):

  • ManifestV2(经典):"permissions": ["https://another-site.com/"]
  • ManifestV3(即将推出):"host_permissions": ["https://another-site.com/"]
于 2019-03-22T02:33:18.523 回答
-3

临时解决方案:使用运行命令浏览器禁用 CORB --disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating

Linux 上的示例运行命令。

对于铬:

chrome %U --disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating

对于铬:

chromium-browser %U --disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating

类似的问题。

来源

于 2019-03-25T08:15:00.853 回答