The same-origin policy (SOP) is a web security mechanism built into web browsers that influences how websites can access one another. Without SOP, a malicious website or web application could access another without restrictions. That would allow attackers to easily steal sensitive information from other websites or even perform actions on other sites without user consent.
SOP does not need to be turned on – it is automatically enabled in every browser that supports it. Developers must be aware of this mechanism when creating web apps that communicate with one another, so they know how to disable it in special circumstances safely.
The same-origin policy is often confused with content security policies. The difference is that content security policies prevent calls to external resources (outbound) while the same-origin policy prevents calls from external resources (inbound). Also, content security policies are not enabled by default and must be defined by developers.
The SOP mechanism was designed to protect against attacks such as cross-site request forgery (CSRF), which basically attempt to take advantage of vulnerabilities due to differing origins. However, because it’s just a browser security policy and has never been defined as a permanent Internet specification, every browser implements it a bit differently. You should thus be careful with relying on SOP because the user may be running a browser with different SOP rules (for example, Internet Explorer).
Note that SOP is entirely useless as a method of protection against cross-site scripting (XSS) because it would have to limit the loading of scripts from different sites, ultimately hindering web application functionality.
To understand the same-origin policy, we need first to understand the term origin.
In web terms, the origin is a set of common characteristics of a web resource. In most cases, the origin is a combination of three elements: the schema (protocol), the hostname (domain/subdomain), and the port. Therefore, all resources identified by the same schema:hostname:port combination have the same origin. However, if two resources differ in any one of these three elements, modern browsers such as Google Chrome or Mozilla Firefox treat these resources as having a different origin. Only in the case of Microsoft Internet Explorer the port number is not considered a part of the origin. For example:
Origin checks are applied by the browser in every case of potential interaction between elements from different origins. This includes, for example:
However, SOP does not completely eliminate the interaction between different origins. The browser evaluates whether a specific interaction could pose a threat and if not, it is allowed. For example:
In some cases, you may want to loosen the tight grip of SOP and allow certain cross-origin interactions, for example, between different domains that both belong to you. In such cases, there are several ways to ensure that SOP does not hinder your web application’s cross-domain interaction capabilities.
The simplest way to change the origin of your site is by declaring it using JavaScript:
document.domain = "example.com";
However, this is only possible for sites within the same domain hierarchy – otherwise, any site could pretend to have your origin. For example, you can use this simple method if you have several microsites under different subdomains, such as login.example.com, blog.example.com, etc.
Note that browsers are on their way to deprecating this approach, so this method is not recommended.
If you need to communicate between window objects such as a page and a popup from that page or a page and an iframe embedded on that page, you can use the window.postMessage() method.
For example, you could get a reference to another window using newWindow = window.opener
and then dispatch a message event through newWindow.postMessage()
. The newWindow
uses the event object to access arguments passed with this method.
Cross-origin resource sharing (CORS) is an HTTP mechanism that uses HTTP headers to define origin permissions. Using CORS headers, you can inform the browser that resources from another origin have the right to access resources on your page.
For example, a GET request to a site may be sent with an Origin request header that declares the exact origin (similar to document.domain
):
GET / HTTP/1.1
Host: www.example.com
(...)
Origin: http://example2.com
In response, the resource that supports CORS will send an Access-Control-Allow-Origin response header:
HTTP/1.1 200 OK
(...)
Access-Control-Allow-Origin: http://example2.com
(...)
The Access-Control-Allow-Origin header may declare a single origin or a wildcard (*
). Of course, using wildcards can be risky, but the option is there for the web application developer.
The above simple scheme is used for HTTP requests that the web browser considers safe. For more risky requests, the web browser first makes sure that cross-origin communication is allowed using a special preflight request. Preflight is required in the following cases:
text/plain
, multipart/form-data
, or application/x-www-form-urlencoded
.The preflight request is an OPTIONS request with CORS headers:
OPTIONS / HTTP/1.1
Host: www.example.com
(...)
Origin: http://example2.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-CUSTOM, Content-Type
In response, the server informs the browser what methods are allowed, whether it accepts the headers, and for how long the preflight request is valid:
HTTP/1.1 204 No Content
(...)
Access-Control-Allow-Origin: http://example2.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-CUSTOM, Content-Type
Access-Control-Max-Age: 86400
After the preflight is complete, you can send regular requests with CORS headers.
If your script attempts to connect to a WebSocket, browsers will allow all such communications without checking the same-origin policy. However, the browser adds an Origin header to the request, specifying the origin of the script from which the connection is coming.
In such a case, it is not the browser but the developer that is expected to ensure safety. If you use WebSockets in this way, you should include functionality on the WebSocket server to compare data in the Origin header with a whitelist of origins that are safe to reply to or use other ways to confirm that a connection can be trusted.
Before cross-origin resource sharing was introduced in 2009, web pages could use JSONP (JSON with padding) to bypass the same-origin policy. This was done by using <script>
tags to retrieve and execute JSON content from other origins. However, when using JSONP, an attacker may be able to replace the original function with a malicious one. Therefore, currently, the use of JSONP is not recommended.
The same-origin policy (SOP) is a web security mechanism built into web browsers that defines how websites can access each other’s content. All modern browsers support the same-origin policy.
Without same-origin policy, a malicious website or web application could access resources from another site without restrictions. That would allow attackers to easily steal sensitive information from other websites or even perform actions on other sites without user consent.
In most cases, web resources have the same origin if they have the same schema (protocol), hostname (domain/subdomain), and port. Only in Internet Explorer, the port number is not considered a part of the origin.
Find out about cookie security flags, which are another web protection mechanism.