Why can browser extensions use "fetch" without cross-origin permissions? - google-chrome-extension

When XMLHttpRequest is being used to do cross-origin requests, permissions are required via manifest.json, as stated here: https://developer.chrome.com/apps/xhr
But when using fetch, it doesn't need it and can requests to all ressources.
What makes fetch different than XMLHttpRequest that it works without persmissions? Or is that just bug?

Related

Getting 2 responses from one http request

When I make a post request to my node.js backend using axios and I look in my chrome console network tab, I see 2 http requests to the endpoint instead of 1.
The first one has a status code of 200 and a response of GET,HEAD,POST
The second one is the one I was expecting which is a status code of 200 and whatever I set my response to be.
Is it normal to get that 1st response of GET,HEAD,POST as well or am I doing something wrong here?
As you indicated that you're using different hosts (or ports at least), this is a default behaviour of browsers to check, if the CORS protocol is understood.
From MDN:
CORS (Cross-Origin Resource Sharing) is a system, consisting of transmitting HTTP headers, that determines whether browsers block frontend JavaScript code from accessing responses for cross-origin requests.
The same-origin security policy forbids cross-origin access to resources. But CORS gives web servers the ability to say they want to opt into allowing cross-origin access to their resources.
You can find more about CORS and prefligh requests in the MDN docs.

Access to XMLHttpRequest ' from origin xxxx blocked by CORS policy: Response to preflight. Redirect is not allowed for a preflight request

I am using Azure maps and have no problem with FF or Edge. However Chrome is giving me the following error when trying to display the map:
Access to XMLHttpRequest at atlas.microsoft.com/map/tile/pbf?&view=Unified&language=NGT&api-version=1.0&layer=basic&style=main&zoom=16&x=12586&y=26496&subscription-key=xxxx' from origin mysite.org has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
I have added mysite.org to allowed origins in Azure. Some of the map contents do display such as the location marker and map style selector etc. Only the actual map is being blocked.
How do I resolve this issue?
The CORS error is most likely a red herring here.
What's happening is that your request for some reason receives a redirect from the server, which therefore gets blocked by CORS
It's likely that this particular URL is not intended to be consumed by Ajax but is meant to be rendered directly by a browser. It could, for example, be an authentication issue where the server is redirecting you to a login page or the map server may just want to reformat your URL.
In any case, open the developer tools in a browser, tell it to not clear the requests on navigation and try to put that URL in; you'll see that some kind of redirect happens in the network tab You then need to figure out how to avoid that redirect - or, if this URL type is not intended for Ajax, rethink your design.
I wrote a bit about how CORS works here; https://www.lytzen.name/2016/02/20/playing-with-cors.html, which may or may not help.

CORS in OAuth: Response to preflight request doesn't pass access control check

So I'm trying to implement the OAuth 2 flow, while my webapp is the server that give away authorization code/access token.
Cors error happens when sending the code back to third-party website(zapier in this case):
XMLHttpRequest cannot load https://zapier.com/dashboard/auth/oauth/return/App505CLIAPI/?code=somecode&state=somestate. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://myurl' is therefore not allowed access.
If I manually open a new tab, paste that zapier uri, everything works perfectly.
Seems like a typical CORS issue, but none the popular solutions works for me:
Add Access-Control-Allow-Origin: I'm using this oauth2orize
library, and sending reponse to preflight seems also part of the
library. So I cannot add header.
Using cors: Have tried app.use(cors()) and app.options('*',
cors()) which should apply to all routes, but simply not working.
My webapp sits on a node express server, in front of which there's an nginx proxy server.
Any idea where the problem might be is appreciated.
The issue that error message indicates isn’t caused by the app code running at https://myurl/. Instead it’s just that https://zapier.com/dashboard/auth/… doesn’t seem to support CORS.
Specifically, the response from that https://zapier.com/dashboard/auth/… URL doesn’t include the Access-Control-Allow-Origin response header, so your browser won’t let your frontend JavaScript code access the response.
It seems like that is all intentional on the part of Zapier—they don’t intend for that auth endpoint to be accessed from frontend AJAX/XHR/Fetch code running in a browser. Instead I guess it’s intended that you only access that auth endpoint from your backend code. Or something.
Anyway there is no way from your side that you can fix the fact the response from that Zapier API endpoint doesn’t include Access-Control-Allow-Origin.
And as long as it doesn’t include Access-Control-Allow-Origin, your browser blocks your frontend code from being able to get to the response—and there’s no way to get your browser to behave otherwise as long as your frontend code is trying to hit that API endpoint directly.
So the only solution is to not hit that API endpoint directly from your frontend code but to instead either set up a proxy and change your frontend code to make the request through that, or else just handle it in some other way in your existing backend code, as mentioned above.
The answer at Why does my JavaScript code receive a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error, while Postman does not? gives some details on how you can set up a special CORS proxy, if you want to go that route.

Origin header in Chrome Extension

I have my api running on node js, where for security reasons, I have set up a middle ware function check the origin header, if it is from my website, then only the api should go ahead. I am finding issues with Chrome Extension, as it does not pass the origin header in the get requests, also in the put requests, it sends something like chrome:// as the origin header. Can somebody help?
Regards,
Manik Mittal
Well, that's how Chrome sets the Origin for extensions. It's not simple to override.
It is, however, possible to override. You'll need to use the webRequest API, specifically a blocking response to onBeforeSendHeaders, to rewrite the origin to whatever you like.
If you add in your manifest.json "permissions": ["https://*/"] you shouldn't have problems with CORS. Or if you want only your API to avoid this, just add your own url.

Why do browser APIs restrict cross-domain requests?

XMLHttpRequests require CORS to work cross-domain. Similarly for web fonts, WebGL textures, and a few other things. In general all new APIs seem to have this restriction.
Why?
It's so easy to circumvent: all it takes is a simple server-side proxy. In other words, server-side code isn't prohibited from doing cross-domain requests; why is client-side code? How does this give any security, to anyone?
And it's so inconsistent: I can't XMLHttpRequest, but I can <script src> or <link rel> or <img src> or <iframe>. What does restricting XHR etc. even accomplish?
If I visit a malicious website, I want to be sure that :
It cannot read my personal data from other websites I use. Think attacker.com reading gmail.com
It cannot perform actions on my behalf on other websites that I use. Think attacker.com transferring funds from my account on bank.com
Same Origin Policy solves the first problem. The second problem is called cross site request forgery, and cannot be solved with the cross-domain restrictions currently in place.
The same origin policy is in general consistent with the following rules -
Rule 1: Doesn't let you read anything from a different domain
Rule 2: Lets you write whatever you want to a different domain, but rule #1 will not allow you to read the response.
Rule 3: You can freely make cross-domain GET requests and POST requests, but you cannot control the HTTP headers
Lets see how the various things you have listed line up to the above rules :
<img> tags let you make a HTTP request, but there is no way to read the contents of the image other than simply displaying it. For example, if I do this <img src="http://bank.com/get/latest/funds"/>, the request will go through (rule 2). But there is no way for the attacker to see my balance (rule 1).
<script> tags work mostly like <img>. If you do something like <script src="http://bank.com/get/latest/funds">, the request will go through. The browser will also try to parse the response as JavaScript, and will fail.
There is a well known abuse of <script> tags called JSONP, where you collude with the cross-domain server so that you can 'read' cross-domain. But without the explicit involvement of the cross-domain server, you cannot read the response via the <script> tag
<link> for stylesheets work mostly like <script> tags, except the response is evaluated as CSS. In general, you cannot read the response - unless the response somehow happens to be well-formed CSS.
<iframe> is essentially a new browser window. You cannot read the HTML of a cross-domain iframe. Incidentally, you can change the URL of a cross-domain iframe, but you cannot read the URL. Notice how it follows the two rules I mentioned above.
XMLHttpRequest is the most versatile method to make HTTP requests. This is completely in the developers control; the browser does not do anything with the response. For example, in the case of <img>, <script> or <link>, the browser assumes a particular format and in general will validate it appropriately. But in XHR, there is no prescribed response format. So, browsers enforce the same origin policy and prevent you from reading the response unless the cross domain website explicitly allows you.
Fonts via font-face are an anomaly. AFAIK, only Firefox requires the opt-in behavior; other browsers let you use fonts just like you would use images.
In short, the same origin policy is consistent. If you find a way to make a cross-domain request and read the response without explicit permission from the cross-domain website - you'll make headlines all over the world.
EDIT : Why can't I just get around all of this with a server-side proxy?
For gmail to show personalized data, it needs cookies from your browser. Some sites use HTTP basic authentication, in which the credentials are stored in the browser.
A server-side proxy cannot get access to either the cookies or the basic auth credentials. And so, even though it can make a request, the server will not return user specific data.
Consider this scenario...
You go to my malicious website.
My site makes an XHR to your banking website and requests the form for bank transfer.
The XHR reads the token that prevents CSRF and POSTs the form alongside the security token and transfers a sum of money to my account.
(I) Profit!!!
Without Same Origin Policy in existence, you could still POST that form, but you wouldn't be able to request the CSRF token that prevents CSRFs.
Server side code does not run on the client's computer.
The main issue with XHR is that they can not just send a request but you are also able to read the response. Sending almost arbitrary requests was already possible. But reading their responses was not. That’s why the original XHR did not allow any cross-origin requests at all.
Later, when the demand for cross-origin requests with XHR arose, the CORS was established to allow cross-origin requests under specific conditions. One condition is that particular request methods, request header fields, and requests that would contain user credentials require a so called preflight request with which the client can check whether the server would allow the request. With this the server has the ability to restrict access to only specific origins as otherwise any origin could send requests.

Resources