Chrome 如何在内容脚本中进行跨源请求(尽管CORS标头正确,但目前仍被CORB阻止)?

ttisahbt  于 2023-03-21  发布在  Go
关注(0)|答案(3)|浏览(227)

我正在开发一个Chrome扩展程序,它可以从某些网站向我控制的API发出请求。在Chrome 73之前,该扩展程序工作正常。升级到Chrome 73后,我开始收到以下错误:
跨源读取阻止(CORB)阻止了MIME类型为application/json的跨源响应http://localhost:3000/api/users/1
根据Chrome's documentation on CORB,如果满足以下所有条件,CORB将阻止请求的响应:
1.该资源为“数据资源”,具体内容类型为HTML、XML、JSON
1.服务器会使用X-Content-Type-Options: nosniff头进行响应,或者如果忽略此头,Chrome会通过检查文件检测到内容类型为HTML、XML或JSON之一

  1. CORS不明确允许访问资源
    此外,根据"Lessons from 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阻止呢?

6l7fqoea

6l7fqoea1#

基于"Changes to Cross-Origin Requests in Chrome Extension Content Scripts"中的示例,我用新方法fetchResource替换了fetch的所有调用,该方法具有类似的API,但将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可序列化对象,所以我们不能简单地将Fetch API Response对象从后台页面传递到扩展。
后台页面不受CORS或CORB的影响,因此浏览器不再阻止来自API的响应。
警告!URL必须添加到manifest.json

  • 对于"host_permissions": ["*://*.example.com/"]中的清单V3
  • 对于"permissions": ["*://*.example.com/"]中的清单V2
i5desfxk

i5desfxk2#

参见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.
    }
  });

允许清单.jsonmore info)中的URL:

  • 清单V2(经典):"permissions": ["https://another-site.com/"]
  • 清单V3(即将发布):"host_permissions": ["https://another-site.com/"]
wixjitnu

wixjitnu3#

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

Linux上的运行命令示例。

对于Chrome浏览器:

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

对于 chrome :

chromium-browser %U --disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating
类似的问题。
Source .

相关问题