2

In the response HTML of a website, with a domain like http://www.example.com, there are many javascript files referenced. One of them references a javascript file on a different domain, and this script tag has the crossorigin="anonymous" attribute set:

<script crossorigin="anonymous" src="//cdn.example.net/script.js"></script>

I've attempted to redirect the request to another url using a Google Chrome extension:

chrome.webRequest.onBeforeRequest.addListener(function(info) {
    return {
        redirectUrl: "http://example.org/custom.js"
    };
}, {
    urls: [
        "*://cdn.example.net/script.js"
    ],
    types: ["script"]
}, ["blocking"]);

However, when I try and load the site I get an error in the javascript console:

Redirect at origin http://cdn.example.net has been blocked from loading by Cross-Origin Resource Sharing policy: Received an invalid response.
Origin http://www.example.com is therefore not allowed access.

If I intercept the response HTML manually (outside of Chrome) and remove the attribute crossorigin="anonymous" it works as expected.

I have the file at http://example.org/custom.js set to send:

Access-Control-Allow-Origin: *

I have also tried removing / modifying the response headers from www.example.com but this does not seem to make a difference. The response headers ( for reference ) from the main frame are:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Vary: Accept-Encoding
Status: 200 OK
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
Cache-Control: no-cache, no-store
X-Frame-Options: SAMEORIGIN
P3P: CP="NOI DSP COR NID ADMa OPTa OUR NOR"
Content-Encoding: gzip

There are other javascript files that load after this one, and depend on it, and I'd like to leave them as they are.

Again, the main issue really seems to be the crossorigin="anonymous" tag ( which from what I can tell supposedly has the primary purpose of choosing whether error information will be exposed )

How can I write a Google Chrome extension to override the javascript that is executed from this source?

Community
  • 1
  • 1
cwd
  • 53,018
  • 53
  • 161
  • 198
  • Are you using `chrome.extension.getURL("http://example.org/custom.js")` or `"http://example.org/custom.js"` as `redirectUrl`? – Rob W Jun 20 '14 at 08:59
  • @RobW - thanks, that was a typo in the question, but actually not the issue. I had also tried adding a `"web_accessible_resources": ["replacement.js"]` before asking the question and that was an artifact from copying / pasting to create the question. Also, I rolled back your edit in order to show that there are three different domains involved here. – cwd Jun 20 '14 at 15:31
  • I've reverted back to `example.org`, `example.com` and `example.net` because these are the officially recognized domains for testing purposes. One of your domains was actually a real domain that is for sale. And note that for the purpose of CORS, `subdomain.example.com` and `example.com` are different. Which Chrome version are you using? – Rob W Jun 20 '14 at 20:20

1 Answers1

3

Your attempted solutions don't work, because the only relevant headers for CORS are those that are served by the original resource. If this CORS check succeeds, then the redirects are checked and so on.

However, it appears that the initial CORS check failed already..I've reported this bug at https://code.google.com/p/chromium/issues/detail?id=387198.

There is a work-around. Since Chromium 35.0.1911.0, you can redirect requests at the chrome.webRequest.onHeadersReceived event. Redirecting a cross-origin request at this stage seems to work if you set the access-control-allow-origin: * together with redirectUrl. A small disadvantage of this approach is that the request is not immediately redirected, but only after receiving a response from the origin request. If the original request results in an error, e.g. a 404, then your redirect won't happen at all. Nevertheless, it is the only way to get the desired effect until the bug is fixed.

chrome.webRequest.onHeadersReceived.addListener(function(info) {
    return {
        responseHeaders: info.responseHeaders.concat([{
            name: 'access-control-allow-origin',
            value: '*' 
        }]),
        redirectUrl: "http://localhost:2222/custom.js"
    };  
}, {
    urls: [
        "*://example.net/script.js"
    ],  
    types: ["script"]
}, ["blocking", "responseHeaders"]);

Note: Regardless of the method, the target of the redirect must also include an appropriate access-control-allow-origin header, or the request will still be aborted with the following error:

Redirect at origin 'http://example.net' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4444' is therefore not allowed access.

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • got it - makes perfect sense. thanks for the detailed response. accepted and +1'd – cwd Jul 06 '14 at 23:31