Same Origin Policy and CORS

What is Origin
The protocol/domain/port tuple of a URL is called the origin
let url = 'http://store.company.com/dir/page.html'
//http://store.company.com is origin
When the two Origins are the same
When the protocol/domain/port tuple of the URL is the same for two URLs than those two urls are said to have the same origin.
What is the same origin Policy?
The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin. The script loaded by evil.com can’t interact with resources from a different origin.
Communication between cross-origin and their categories
cross-communication between cross-origin is divided into three categories
Cross-Origin Writes: All cross-origin redirects, clicking on link, http requests calling, comes under this category. It is allowed by default.
Cross-Origin Embeds: sub resources loading by <img>, <link>, <script>, <video>, <audio>, <embed>, <iframe> comes under this category. It is allowed by default.
Cross-Origin Reads: Reading of subresources or responses loaded by ajax/fetch calls comes under this category. It is restricted by default.
Role of CORS in cross-origin communication
With CORS (cross-origin resource sharing) we ensure safer cross-origin reads.
How CORS works under the hood for HTTP requests
There are two types of cross-origin requests:
Safe requests.
All the others (Unsafe Request, Request with Credentials).
A request is safe if it satisfies two conditions:
Safe method: GET, POST, or HEAD
Safe headers – the only allowed custom headers are:
Accept
,Accept-Language
,Content-Language
,Content-Type
with the valueapplication/x-www-form-urlencoded
,multipart/form-data
ortext/plain
.
Any other request is considered “unsafe”. For instance, a request with PUT
method or with an API-Key
HTTP-header does not fit the limitations.
Safe Requests
GET /request
Host: anywhere.com
Origin: <https://javascript.info>
...
The server can inspect the Origin
and, if it agrees to accept such a request, add a special header Access-Control-Allow-Origin
to the response. That header should contain the allowed origin (in our case https://javascript.info
), or a star *
. Then the response is successful, otherwise, it’s an error.
The browser plays the role of a trusted mediator here:
It ensures that the correct
Origin
is sent with a cross-origin request.It checks for permitting
Access-Control-Allow-Origin
in the response, if it exists, then JavaScript is allowed to access the response, otherwise, it fails with an error.
200 OK
Content-Type:text/html; charset=UTF-8
Content-Length: 12345
Content-Encoding: gzip
API-Key: 2c9de507f2c54aa1
Access-Control-Allow-Origin: <https://javascript.info>
Access-Control-Expose-Headers: Content-Encoding,API-Key
Unsafe Request
We can use any HTTP-method: not just GET/POST
, but also PATCH
, DELETE
and others.
Some time ago no one could even imagine that a webpage could make such requests. So there may still exist webservices that treat a non-standard method as a signal: “That’s not a browser”. They can take it into account when checking access rights.
So, to avoid misunderstandings, any “unsafe” request – that couldn’t be done in the old times, the browser does not make such requests right away. First, it sends a preliminary, so-called “preflight” request, to ask for permission.
A preflight request uses the method OPTIONS
, no body and three headers:
Access-Control-Request-Method
the header has the method of the unsafe request.Access-Control-Request-Headers
the header provides a comma-separated list of its unsafe HTTP headers.Origin
the header tells from where the request came. (such ashttps://javascript.info
)
If the server agrees to serve the requests, then it should respond with an empty body, status 200, and headers:
Access-Control-Allow-Origin
must be either `` or the requesting origin, such ashttps://javascript.info
, to allow it.Access-Control-Allow-Methods
must have the allowed method.Access-Control-Allow-Headers
must have a list of allowed headers.Additionally, the header
Access-Control-Max-Age
may specify a number of seconds to cache the permissions. So the browser won’t have to send a preflight for subsequent requests that satisfy given permissions.
After a successful preflight request, the main HTTP request is made as shown in the safe request.
Request with Credentials
The most interesting capability exposed by both XMLHttpRequest
Fetch and CORS is the ability to make "credentialed" requests that are aware of HTTP cookies and HTTP Authentication information. By default, in cross-origin XMLHttpRequest
or Fetch invocations, browsers will not send credentials. A specific flag has to be set on the XMLHttpRequest
object or the Request
constructor when it is invoked.
Why?
That’s because a request with credentials is much more powerful than one without them. If allowed, it grants JavaScript the full power to act on behalf of the user and access sensitive information using their credentials.
To send credentials in fetch
, we need to add the option credentials: "include"
and in XMLHttpRequest
we need to add withcredentials: true
. If the server agrees to accept the request with credentials, it should add a header Access-Control-Allow-Credentials: true
to the response, in addition to Access-Control-Allow-Origin
.
Subscribe to my newsletter
Read articles from Shailendra Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
