16

I wrote a chrome web extension to avoid CORS limitation when developing my own web apps. The extension is a developers' tool and used to proxy the request from the source url to the dest url.

The extension core code like this, thus developers can develop their pages on my site and request to their server side without CORS limitation:

chrome.webRequest.onBeforeRequest.addListener(details => {
  let redirectUrl = '';
  //...
  redirectUrl = details.url.replace(TNT.validRules[i].source, TNT.validRules[i].dest);
 return {redirectUrl}
}, {urls: ['<all_urls>']}, ['blocking']);


chrome.webRequest.onHeadersReceived.addListener(details => {
  details.responseHeaders.map(item => {
    if (item.name.toLowerCase() == 'Access-Control-Allow-Origin'.toLowerCase()) {
      item.value = '*'
    }
  })
  return {responseHeaders};
}, {urls: ['<all_urls>']}, ["blocking", "responseHeaders"]);

But the latest Chrome 72 cannot proxy the request. And the console errors are:

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://xxxxxxx.com/abc.json?siteId=69 with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.

user9106242
  • 183
  • 1
  • 1
  • 6
  • Perform the request in your background page and send the results to your content script via messaging. – wOxxOm Feb 20 '19 at 12:43
  • Indeed I add an eventListener onHeadersReceived and set 'Access-Control-Allow-Origin'='*' in the background.js. The extension works well before chrome 72. But it does not work now. – user9106242 Feb 20 '19 at 13:02
  • Just stumbled upon the [official explainer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/extension-content-script-fetches#TOC-2.-Avoid-Cross-Origin-Fetches-in-Content-Scripts) that demonstrates what I said above. – wOxxOm Feb 20 '19 at 20:11
  • Thanks.That's the reason why the extension not work. I still need to figure out how to solve the problem.Do not know how many costs it will take :( – user9106242 Feb 21 '19 at 02:32
  • @wOxxOm Sorry for my poor english. Do the codes explain my question clearly? – user9106242 Feb 21 '19 at 06:20
  • I think this is the same problem with mine. https://bugs.chromium.org/p/chromium/issues/detail?id=933893 – user9106242 Feb 22 '19 at 02:35
  • I still don't get why you need such a convoluted approach instead of making the requests in the background script, but if the issue you've linked is indeed relevant, all you need is to add 'extraHeaders' as explained in the comments there and in the documentation. – wOxxOm Feb 22 '19 at 04:24
  • The extension is a develop tool to enable CORS for testing purposes. I will have a try as the comments said. Thank you very much for your patience. – user9106242 Feb 22 '19 at 06:28
  • This sudden CORB restriction for content scripts is asinine, especially since there was no communication sent out to developers to notify of this upcoming deprecation. There are surely PLENTY of background script extensions that need to make API calls to work properly. And what about when we are using third party components that make api calls, which we do not have control over? – Roman Scher Mar 21 '19 at 22:31

2 Answers2

13

I've found answer in the google docs:

Avoid Cross-Origin Fetches in Content Scripts

Old content script, making a cross-origin fetch:

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 => ...)

New content script, asking its background page to fetch the data instead:

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

New extension background page, fetching from a known URL and relaying data:

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

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

Ben Winding
  • 10,208
  • 4
  • 80
  • 67
Oleksii.B
  • 618
  • 8
  • 16
  • 1
    Main answer should be updated with this answer. Thanks! – Gorzas Aug 27 '19 at 09:39
  • The solution is to use some browser-specific API? What is this, IE all over again? :-| – Josh M. Aug 19 '21 at 17:41
  • I was trying to call the Mixpanel API to send data and [Edge was blocking](https://learn.microsoft.com/en-us/microsoft-edge/web-platform/tracking-prevention) the requests. Although I was able to get it to work by changed the setting in edge, this is the correct way to implement it. This helped me, thank you. – Gangula Aug 07 '23 at 17:24
9

See this issue filed by co-founder at Moesif.

https://bugs.chromium.org/p/chromium/issues https://bugs.chromium.org/p/chromium/issues/detail?id=933893

Based on his discussion with Chronium engineers, basically, you should added extraHeaders into extra options for when adding listeners, which will pull this trigger closer to the network and inject the headers before CORB gets triggered.

chrome.webRequest.onHeadersReceived.addListener(details => {
  const responseHeaders = details.responseHeaders.map(item => {
    if (item.name.toLowerCase() === 'access-control-allow-origin') {
      item.value = '*'
    }
  })
  return { responseHeaders };
}, {urls: ['<all_urls>']}, ['blocking', 'responseHeaders', 'extraHeaders'])

Btw, a little self promotion here. Why don't you just use our CORS tool,

https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc?hl=en

It is already the most feature complete CORS tool.

Community
  • 1
  • 1
Derrick
  • 1,508
  • 11
  • 8
  • 1
    Using Chrome 72.0.3626.121 I get past the CORS extension, but the request dies with: core.js:15723 ERROR TypeError: rxjs__WEBPACK_IMPORTED_MODULE_2__.Observable.throw is not a function at ApiService.push../src/app/services/api.service.ts.ApiService.logError (api.service.ts:49) at CatchSubscriber.selector (api.service.ts:16) at CatchSubscriber.push../node_modules/rxjs/_esm5/internal/operators/catchError.js.CatchSubscriber.error (catchError.js:34) ,,, – AUSTX_RJL Mar 05 '19 at 16:03
  • 1
    I am using the cors tool, and this solved it for me. Thanks Derrick – jivanrij Apr 04 '19 at 04:18
  • @derrick is 'blocking' option necessary in this example? – oxfn May 06 '19 at 10:28
  • Thanks for saving my head from banging it to wall. Only solution that worked for me is the Moesif CORS tool. – coderpc Nov 06 '19 at 22:32