This document and related tech talks are meant to be “just enough to fully grasp what’s happening”. Aimed primarily at API/backend developers who are sometimes confused about why they are “seeing errors about CORS”.
I'm always looking for feedback, better examples, and corrections – especially with a document as technical as this one.
I hope to provide just enough information to fully grasp the what-and-why of CORS, empowering you to “know what to google”, should this not be enough.
Hope it’s helpful!
wget, server-side scripts, etc, don’t have to care about CORS.
http://my.example.com(less obvious; different host)
Less foundational, but this is what it does:
Suppose I accidentally open a link to https://evil.example.com/. That page runs a script to automatically send a GET request from my browser to FOR EXAMPLE, https://bank.example.com/logged-in-views/my-private-info?format=json
The web browser includes a header on this request: “Origin: https://evil.example.com”
Your web browser is extremely “helpful”. Assuming you had already been logged in, it will send along your existing login cookie info in the request. (evil.example.com can’t just read other domain cookies, so it has to make a genuine, in-browser request).
When the browser receives the response from the server, the browser examines the headers on the response before determining if the requester can read it.
If the server did not send along a header called
Access-Control-Allow-Origin, it will make a safe assumption that the owners of the server do not want to share data across Origins. This is Same-origin Policy at work! So the browser — despite receiving the data — will not let the requesting document READ or access that response.
If the bank server did send an
Access-Control-Allow-Origin header on the response, the browser will compare the values provided in that header to the Origin of the document that made the request.
*” (a wild-card), the browser knows that the owners of the server want to allow ANY origin to access that response.
To paraphrase some docs:
If the resource owners at
https://api.example.com wished to restrict access to the resource to requests only from
https://www.example.com, (i.e no domain other than
https://www.example.com can access the resource in a cross-origin manner) they would send:
So it’s always up to the server to look at an “Origin” header, and determine if it should send back an
Access-Control-Allow-Origin header on the response. And if it should, what value does it want to supply?
To allow from a specific domain, this could be as simple as the following:
if request.headers['origin'] == 'https://trusted.example.com': response.headers['access-control-allow-origin'] = 'https://trusted.example.com'
When you want an Origin other than your own to have browser-based access to your resource.
This all comes into play in cases where a website might be
https://www.bible.com/ but needs to be able to make API Fetch calls to
https://api.bible.com/ on the client side (in the browser).
The Fetch spec (that defines CORS) has a category of requests referred to as “simple requests”. Those don’t send an automatic “preflight” request. But, all others do.
To directly quote (emphasis mine) (cite):
… for “preflighted” requests the browser first sends an HTTP request using the
OPTIONSmethod to the resource on the other origin, in order to determine if the actual request is safe to send. Such cross-origin requests are preflighted since they may have implications for user data.
For example: If a preflight check describing a request for
DELETE bank.example.com/my-account fails, the browser should not send that
The preflight request will usually contain headers that describe the “real” request that it intends to make:
Access-Control-Request-Method, which will contain, for example,
POSTif the method of the intended request is a POST request.
Access-Control-Request-Headers, which will contain a comma separated list of “non-standard” headers that the request intends to send along. E.g., including headers like
This preflight request gives the server a chance to confirm or deny that a given request method, set of headers, and provided Origin are allowed or disallowed.
That response to a preflight might include several headers, for example:
Access-Control-Allow-Origin(you know this one!)
Access-Control-Allow-Methods(POST, GET, OPTIONS)
Access-Control-Allow-Headers(X-PINGOTHER, Content-Type, X-Secret-API-Token)
CORS configuration allows opting out of certain protections provided by Same-origin Policy. It does not necessarily enhance security at all.
You must still protect against CSRF explicitly, especially in the case of state-changing requests. As well as considering solutions like Content Security Policy to prevent certain XSS and data injection attacks.
CORS is part of the Fetch API spec. It’s a way to enable read-access to cross-origin requests, which are blocked by default per the Same-origin policy.
There’s actually a lot more to be said about both. CORS has way more options to define more-or-less strict behavior. Some of which were hinted at with the list of
Access-Control-Allow-* headers mentioned above.