10. Same-Origin Policy and Cross-Origin Resource Sharing

10. Same-Origin Policy and Cross-Origin Resource Sharing

1. SAME-ORIGIN POLICY INTRODUCED

Same-Origin Policy (SOP) is a major security concept that is built-in in all contemporary browsers. Its main goal is to prevent access attempts of dynamic web page elements (like scripts) to data on resources of a different origin.
In the security context, SOP prevents malicious web sites from retrieving confidential data from restricted locations on behalf of users and without their acknowledgment.
User agents that are compliant with SOP, restrict requests issued from one origin to another origin. For example, popular JS libraries such as JQuery, XmlHttpRequests and Fetch API follow the Same-Origin Policy.
In the right pane, you can see the animated diagram of how SOP works when enabled in the browser.

imageimage

2. ORIGIN DEFINED

To identify an origin, SOP uses the scheme, the hostname (domain name with or without subdomains, or IP address), and the port number. If those three parameters of two resources match, then these resources have the same origin.
In the right pane, there is a table that shows which URLs have the same origin, and which don’t.

image

3. SAME-ORIGIN POLICY DISABLED

Let us consider an example where there is no Same-Origin Policy at all.
Bob creates a website coolnews.me with funny cat pictures and adds there a basic javascript that makes a request to the website of a popular social network friendslist.me, reads the contents of a page with personal details exactly as the authenticated victim would, both body and headers, and sends them to Bob’s server.
If he shares a link to his website on his social network page, then everyone who follows that link will involuntarily share their personal details with Bob.

image

4. SAME-ORIGIN POLICY ENABLED

With Same-Origin Policy enabled, the browser allows only some basic HTTP requests (e.g. GET and POST requests without any custom HTTP headers) from the resource of one origin to the resource of another origin, and will never allow a script from the Coolnews.me to read the response from the Friendslist.me (unless CORS is also enabled).
In the case with Bob’s malicious page, the browser will first send a preflight request to the Friendslist.me website to ensure that the request is allowed, and, since Friendslist.me knows nothing about Coolnews.me and doesn’t trust it, it disallows the access. The browser will then prevent the malicious request from ever being sent.

image

5. CROSS-ORIGIN RESOURCE SHARING INTRODUCED

Cross-Origin Resource Sharing (CORS) is a way to deliberately disable SOP. We may need it for implementation of some business logic that requires sending requests to another origin, like performing interactions with cloud services, creating a single-page design, using sharing or liking functionality, etc.
The main idea of CORS is to negotiate with the server on the conditions of the cross-origin request. As a result, either a resource from one origin will be allowed to send an HTTP request to the resource from another origin and read the contents of the response, or the request will be aborted due to the disabled cross-origin resource sharing.
In the right pane, you can see that the cross-origin request to the server that provides stock market quotes for the news website was aborted.

image

6. PREFLIGHT REQUEST CONDITIONS

For the requests that do not meet the requirements below, negotiation on the conditions of the cross-origin request is performed using a preflight request. Preflight requests are triggered when the following conditions are NOT met.
1. An initial cross-origin request uses GET, HEAD or POST methods. For POST method, only application/x-www-form-urlencoded, multipart/form-data, or text/plain content types are allowed.
2. The cross-origin request doesn’t contain custom HTTP headers and includes only the headers explicitly allowed by the CORS policy.
3. No event listeners are registered on an XMLHttpRequestUpload object that is used in the cross-origin request.
4. No ReadableStream objects are used in the cross-origin request.
In other words, a cross-origin request that meets the conditions above doesn’t trigger the preflight request.
Instead of the preflight request, negotiation on the conditions is performed using the Origin header in the request, and the Access-Control-Allow-Origin header in the response. If the Access-Control-Allow-Origin header contains the specified origin or an asterisk, the content of the response becomes accessible to the code that performed the request.
In the right pane, you can see the example of the code that triggers the preflight request.

image

7. PREFLIGHT REQUEST

When the preflight request is triggered, the initial request is postponed until the server confirms the properties of the request to be sent. The preflight request is an HTTP OPTIONS request that contains Origin header and may include CORS-specific headers.
In the right pane, you can see the example of the preflight request with highlighted headers.

image

8. CROSS-ORIGIN COMMUNICATION HEADERS

CORS mechanism uses several HTTP headers to agree on cross-origin communication parameters.
In the right pane, click the header you want to explore, and the description will appear instantly.

image

Origin
This header indicates the origin that initiates a request

Access-Control-Request-Method
This header indicates the HTTP request methods that will be used in the further cross-origin request

Access-Control-Request-Headers
The header indicates the headers that will be used in the further cross-origin request

Access-Control-Allow-Origin
The header specifies the origin that may access the requested resource. If the header value is * then any origin may access the resource.

Access-Control-Max-Age
The header specifies how long information from Access-Control-Allow-Methods and Access-Control-Allow-Headers should be cached.

Access-Control-Allow-Credentials
The header indicates that the server will accept the original request if it contains credentials. In this case, credentials may be one of the following: HTTP cookies, TLS certificates, and HTTP authentication headers.
In order to use credentials, the requesting origin should declare that their usage explicitly e.g. set XHRObject.withCredentials = true or set a fetch request credentials mode to “include”.
The header usually contains “true” value or is not present.

Access-Control-Allow-Methods
The header specifies the method or methods that may be used in the original cross-origin requests to the resource.

Access-Control-Allow-Headers
The header specifies the headers that may be used in the original cross-origin requests to the resource. Simple response headers are available by default, but custom headers will require whitelisting.

Access-Control-Expose-Headers
The header specifies the list of headers that browsers are allowed to access in the original cross-origin header when a requester processes the response.

9. EXAMPLE WITH DISABLED CORS

Let us first consider the example of a simple HTTP request with CORS disabled on the server.
Coolnews.me website sends a GET request to the Friendslist.me server using the code displayed in the console at the left.
And that results in the request displayed in the console at the right.

image

9. EXAMPLE WITH DISABLED CORS

Let us first consider the example of a simple HTTP request with CORS disabled on the server.
Coolnews.me website sends a GET request to the Friendslist.me server using the code displayed in the console at the left.
And that results in the request displayed in the console at the right.

Friendslist.me server sends a response, but because “Access-Control-Allow-Origin: https://coolnews.me” header is not present in the response, the browser with Coolnews.me website won’t let it access the data from the response and will show an error in the browser console.

image

10. EXAMPLE WITH ENABLED CORS WITHOUT PREFLIGHT

In this example, we still have a simple HTTP request, but CORS is enabled on the server.
Bizent.me website sends a GET request to the Lotsofgoods.me server using the code displayed in the console at the left.
And that results in the request displayed in the console at the right.

image

There’s no preflight request because the conditions for it are not met.
Lotsofgoods.me server sends a response, where Access-Control-Allow-Origin: https://bizent.me is present, thus enabling the browser to give Bizent.me access to the content of the response.

image

11. EXAMPLE WITH PREFLIGHT REQUEST

In our third example, the request contains a custom HTTP header, so, according to the conditions described earlier, the preflight request is triggered.
Bizent.me website sends a GET request with a custom header X-User-Tracker-Id to the server of Lotsofgoods.me using the code displayed in the code pane at the left.
And that results in the preflight request displayed in the code pane at the right.

image

The browser sends a preflight request to Lotsofgoods.me because javascript on Bizent.me crafts a request with a custom header. The server of Lotsofgoods.me sends a response to a preflight request.
In that response, Access-Control-Allow-Origin: https://bizent.me is present, but X-User-Tracker-Id header is not. This means that the server of Lotsofgoods.me allows cross-origin requests from BizeEnt.me, but doesn’t allow X-User-Tracker-Id header in the request.
The browser processes the response from Lotsofgoods.me to the preflight request, doesn’t find all the necessary headers that allow the cross-origin request with the specified parameters, blocks the request, and displays the error in the browser console.

image

12. EXAMPLE WITH PREFLIGHT REQUEST

In the final example, CORS is enabled and allows the request performed by bizent.me.
Bizent.me website sends a GET request with a custom header X-Custom-Header to the server of Lotsofgoods.me using the code displayed in the console at the left.
And that results in the preflight request displayed in the console at the right.

image

The browser sends a preflight request to Lotsofgoods.me because Bizent.me makes a request with a custom header. The server of Lotsofgoods.me sends a response to a preflight request.
In that response, both Access-Control-Allow-Origin: https://bizznt.me and Access-Control-Allow-Headers: X-User-Tracker-Id headers are present. This means that the server of Lotsofgoods.me allows cross-origin requests from Bizent.me with a X-User-Tracker-Id header in the request.

image

The browser processes the response from Lotsofgoods.me to the preflight request, finds all the necessary headers that allow cross-origin request initiated by bizent.me and sends the original request.

image


Comments are closed.