0

I am developing an extension for Google Chrome, which need to call some REST Api outside. My problem is I can't invoke API with http protocol while I can with https. Here is my permission configuration:

"permissions": [
        "tabs",
        "storage",
        "cookies",
        "http://*/*",
        "https://*/*"
    ]

And here is the jQuery code to invoke outside sites:

var host =  "https://www.google.com.vn/";
    var xhr = new XMLHttpRequest();
    xhr.open("GET", host, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status === 200) {
                alert(xhr.responseText)
            } else {
                alert("Error with status:" + xhr.status);
            }
        }
    }
    xhr.send();

Above code work correctly with https sites, eg: https://www.google.com.vn/, https://www.linkedin.com/, ... but not working with http site such as: http://stackoverflow.com/

I am Android/iOS developer and I am really new with Chrome Extensions as well as jQuery. Please help to point me my mistake. Thanks in advance.

Nguyen Minh Binh
  • 23,891
  • 30
  • 115
  • 165
  • 1
    See [Chrome extension XMLHttpRequest: Content Security Policy directive](http://stackoverflow.com/a/28237818) or similar questions by searching for `chrome extension XMLHttpRequest content_security_policy` – wOxxOm Jul 16 '16 at 16:33

2 Answers2

3

If you make Ajax call in content scripts, it will be restricted by the Content-Security-Policy header of the web page, which you couldn't (In fact shouldn't since you could remove that header via chrome.webRequest api, however that's bad and would put the site insecure) control.

One ideal suggestion would be moving the logic of sending ajax call to Background (event) page, which lives in the extension context and as long as you declared corresponding host permissions, you could feel free to use it. See Cross-Origin XMLHttpRequest for a detailed reference.

Haibara Ai
  • 10,703
  • 2
  • 31
  • 47
  • Thanks. You saved my head. :) – Nguyen Minh Binh Jul 18 '16 at 09:01
  • That shouldn't really be the case. Content scripts [are not "generally" subject to the page's CSP, and even override the page's CSP for immediate execution of injected scripts](https://developer.chrome.com/extensions/contentSecurityPolicy#interactions). – Xan Jul 18 '16 at 10:56
  • @HaibaraAi Added an answer with the actual reason for the failure. – Xan Jul 18 '16 at 11:01
  • @Xan, thanks for correcting that. When content scripts make ajax call, it's restricted by the Cross-domain settings (for example CORS header), while CSP in fact control whether remote scripts could be loaded. Is that right? – Haibara Ai Jul 18 '16 at 11:05
  • CSP of the page does not apply to content script context, and CORS-overriding permissions from manifest apply. CSP _can_ control where outgoing requests can go; it's just that isolated world of content scripts ignores that. – Xan Jul 18 '16 at 11:06
  • @Xan, yep, I mean leaving a web page alone (no extension/content scripts), CSP is for remote scripts/eval/... while CORS is for cross-domain requests. And yes I just got to know CSP of the page doesn't apply to content scripts... – Haibara Ai Jul 18 '16 at 11:10
  • [CSP directive `connect-src`](https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives#connect-src) defines where XHRs can go. Think of it like this: you have an origin page A and remote resource B. CSP header comes from A and CORS header comes from B, and both influence whether XHR succeeds. Both are fine-grained security mechanisms, but CSP is by default permissive and CORS by default (if missing) restrictive. – Xan Jul 18 '16 at 11:14
  • @Xan, I thought CSP only affected `` and won't block `XMLHTTPRequest`. Seems I'm incorrect and I REALLY should take a deep look at them. – Haibara Ai Jul 18 '16 at 11:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/117598/discussion-between-xan-and-haibara-ai). – Xan Jul 18 '16 at 11:17
  • Thank you for your help, I confirm that I can send request to http sites at background script. What I have to do is send an event from content script to background script to start the task. – Nguyen Minh Binh Jul 18 '16 at 12:01
3

Since you're saying that it works for HTTPS, but not HTTP requests, then it's a problem of web security.

If your content script operates on https://example.com, that technically is the origin of the code, which is considered a secure origin. Web security blocks outgoing connections to insecure origins from secure origins, and that impacts your code.

Haibara's answer is incorrect in assuming that it's a CSP issue; however, the proposed workaround is correct. If you delegate the request to your background page, the code's origin becomes chrome-extension://yourextensionidhere/, and that is expressly allowed to connect to insecure origins.

Xan
  • 74,770
  • 16
  • 179
  • 206
  • Thanks for your focusing on my problem, I still don't understand about `chrome-extension://yourextensionidhere/`. Could you please give me an example? Btw, Now I can call Http site at background scripts (see above comment of mine). – Nguyen Minh Binh Jul 18 '16 at 12:04
  • In `chrome://extensions` UI in developer mode, you can see the ID of your extension. That's the `yourextensionidhere` in the URL of extension pages. For example, if you have a `background.scripts` defined in an extension with ID `banlckihmmpgfoadeppjepaccpnlnama`, the URL of the background page will be `chrome-extension://banlckihmmpgfoadeppjepaccpnlnama/_generated_background_page.html`. – Xan Jul 18 '16 at 12:06
  • hmm, You talking a lot CSP and chrome extensions, but How to sold my problem without calling from background script? The problem is I can not call http sites, since I can with https. How to solve? – Nguyen Minh Binh Jul 18 '16 at 12:11
  • 1
    You cannot; this is not a CSP problem but "basic" web security in Chrome that you cannot override if your content script is in a HTTPS origin. You need to delegate it to the background page. But, to be fair, the "correct" way to solve it is to not use HTTP APIs due to inherent security risks. – Xan Jul 18 '16 at 12:12
  • Ok, clear. So, the answer of Haibara is a workaround. Right? – Nguyen Minh Binh Jul 18 '16 at 12:24
  • That's what the last paragraph of my answer says. – Xan Jul 18 '16 at 12:27