What Is Same-Origin Policy

Same-Origin Policy (SOP) is a rule enforced by web browsers, which controls access to data between websites and web applications. Without SOP, any web page would be able to access the DOM of other pages. This would let it access potentially sensitive data from another web page as well as perform actions on other web pages without user consent.

SOP is not an Internet standard or a fixed rule but rather a general browser security policy. It is interpreted differently by different browsers. It also works differently for different technologies, for example, for cookies. However, the general idea remains the same: to help make sure that there is not unauthorized cross-site access.

What Is the 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 schema:hostname/anything:port have the same origin. However, if even one of the three elements is different, modern browsers such as Google Chrome or Mozilla Firefox consider the resources as having a different origin. Only in the case of Microsoft Internet Explorer, the port is not considered a part of the origin. For example:

  • http://www.example.com/page.html and http://www.example.com/subpage/page2.html HTML documents have the same origin: the protocol is HTTP, the domain is www.example.com, and the port is 80.
  • http://www.example.com/page.html and https://www.example.com/page.html have a different origin due to a different protocol (HTTP vs HTTPS).
  • http://www.example.com/page.html and http://example.com/page.html have a different origin: the subdomain (hostname) is different (www.example.com vs example.com).
  • http://www.example.com/page.html and http://www.example.com/page.html:8080 have a different origin due to a different port (80 vs 8080). However, in Internet Explorer, they have the same origin.

When Is Same-Origin Policy Applied

Origin checks are applied by the browser in every case of potential interaction between elements from different origins. This includes, but is not limited to:

  • JavaScript code and the Document Object Model (DOM), for example, a page cannot access the content of its iframe unless they are of the same origin.
  • Cookies, for example, your session cookie for a particular site cannot be sent to a page with a different origin. However, in the case of cookies, schema and port are not evaluated, only the domain/subdomain.
  • AJAX calls (XmlHTTPRequest).

However, SOP does not completely eliminate the interaction between different origins. The browser evaluates whether this interaction may pose a threat and if not, it is allowed. For example:

  • You can usually write between origins. For example, you can create cross-origin links and you can submit forms cross-origin.
  • You can usually embed between origins. For example, you may use content from a different origin in an iframe (if X-Frame-Options allows it) or embed an img, a css, or a script from a different site.
  • However, reading between origins is usually blocked. This often means that you can send a cross-origin request but cannot read the reply.

How To Loosen SOP

In some cases, you may want to loosen the tight grip of SOP and allow certain cross-origin interaction, for example, between different domains that both belong to you. In such cases, there are several ways that you can ensure that SOP does not hinder your web application cross-domain interaction capabilities.

Declaring the Origin

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. If not, any site could pretend to have your origin. You can use this simple method, for example, if you have several microsites using different subdomains such as login.example.com, blog.example.com, etc.

Cross-Origin Resource Sharing

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 rights 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, a list of origins, or a wildcard (*). Of course, wildcard use is very risky but nevertheless up to the web application developer.

Preflight Requests

The above simple scheme is used for requests that the web browser considers as 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:

  • If there is a custom HTTP header present in the request (any other header except Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width).
  • If the method of the request is PUT, DELETE, CONNECT, OPTIONS, TRACE, or PATCH.
  • If the request is a POST request but the Content-Type is not text/plain, multipart/form-data, or application/x-www-form-urlencoded.
  • If the XMLHttpRequestUpload has at least one event listener registered on it.
  • If you use a ReadableStream object in the request.

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 is the preflight request 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 preflight is complete, regular requests with CORS headers may be sent.

Is SOP Enough To Prevent Attacks?

Same-Origin Policy on its own increases security but is not enough to prevent all Cross-Site Request Forgery (CSRF) attacks, which basically are an attempt to take advantage of different origins. That is why anti-CSRF tokens should still be used as an additional form of protection. SOP is also completely useless as a method of protection against Cross-site Scripting (XSS) because it would have to limit loading of scripts from different sites and that would completely hinder the functionality of web applications.

Therefore, while SOP is an effective means of protection against the obvious, it cannot be considered a foolproof protection mechanism. However, it is a mechanism that web developers must understand and use.

Share this post
Tomasz NideckiTomasz Andrzej Nidecki Technical Content Writer
LinkedIn: https://mt.linkedin.com/in/tonid

Tomasz Andrzej Nidecki (also known as tonid) is a Technical Content Writer working for Acunetix. A journalist, translator, and technical writer with 25 years of IT experience, Tomasz has been the Managing Editor of the hakin9 IT Security magazine in its early years and used to run a major technical blog dedicated to email security.