Home Basics of Same Origin Policy (SOP)
Post
Cancel

Basics of Same Origin Policy (SOP)

The same-origin policy is a web browser security mechanism that aims to prevent websites from attacking each other. It causes the web browser to permit or restrict scripts contained in one web page to access data in the second web page (allowed if both web pages have the same origin). An origin is a combination of URI scheme (http, https, ftp, etc.), domain, and port number. This policy prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page’s Document Object Model (DOM). When a browser sends an HTTP request from one origin to another, any cookies, including authentication session cookies, relevant to the other domain are also sent as part of the request. This means that the response will be generated within the user’s session, and include any relevant data that is specific to the user. Without SOP, if a user visits a malicious website, it would be able to read all data from other web pages. SOP generally controls the access that JavaScript code has to content that is loaded cross-domain.

For example → any page can load images, video and scripts using respective tags. However, any JS code on the page won’t be able to read the content of these resources under SOP. It is possible to relax same origin policy using document.domain. Thus allows the relaxation of SOP for a specific domain, but only if it’s a part of the web page’s FQDN. Case by explanation of SOP is at → Same-origin policy: The core of web security @ OWASP Wellington. The video explains the details on the behavior of webpages in different situations under SOP. Most of these details in a written form follow below.

SOP basically answers the question about whether one site can access data from another site. Not accessing files through a browser basically bypasses SOP. Two sites loaded on different tabs on the web browser are two separate instances on which SOP is enforced. On a tab, the developer tools tab of console allows one to do anything that the website can do permission wise.

Demo 1 → Windows

Assume there are two sites → Site A (red) and Site B (blue). They have the letters A and B on their DOM respectively. A new window opened by the JS on one page, which will open it on a new tab. With that reference, the JS can access the elements of the webpage opened in the new tab.

This behavior is different for different origins → It it completely allowed for the same origin, but because of SOP, the JS cannot access the data from a different origin than the page that contains or calls it.

Each tab or windows is isolated as different environments with a DOM and JS code in it, which can correspond to same or different origins. The site that is opened in a new tab has a window.opener method to refer to which website opened it. The body cannot be accessed under the SOP, but the location itself can be changed (coupon website analogy).

Demo 2 → Frames

The same behavior can be observed with frames and iframes. A parent site can have access to child frames only if they are the same origin. Parent can refer to the frames by window.frames[i] while the frames can refer to the parent by using window.parent. Assume a parent site (paremtsite.com) has 2 frames sitea.com and siteb.com. The parent cannot access the DOM of the children because they are of different origins. Similarly, the frames cannot access the parent’s DOM but can change the location. This can have ads loaded in iframes changing the location of the parent page to phishing google SSO, for example.

SOP applied to general Web designs

This covers two types of scenarios → one, where a site of origin A tries to access the data from another site of origin B inside a web browser (like in different frames) and the other, where it accesses the data from the web server of site B.

Anchor tags

<a href="http://siteb.com/"> is how an anchor tag is defined. The response loads in a new context, so the originating site is replaced by the accessed site. Any site can link to another site but it can’t read the response.

Images

Any site can display images from any other site like → <img src="http://siteb.com/pic.jpg"/>. However, sites cannot read the image data from the other sites. This also applies to other static media like movies, audio, etc.

Javascript

Any site can include JS from any other site. It runs in the originating site. Since it runs inside the originating site, it can potentially attack it (XSS).

Cookies

Cookies for a site are stored inside a cookie jar for that site. A site from a different origin does not have access to the cookies of the first site. But if the site has a post form which posts to the first site, then the cookies are added automatically which also enables CSRF. Cookies’ origin is a tuple of name, domain and path (which means they are broadened to the parent site).

Forms

<form action="http://siteb.com/" method="POST">. The response loads in a new context, so the originating site is replaced by the accessed site. Any site can POST to another site but it can’t read the response.

CSS (cascading style sheets)

Any site can include CSS from any other site but can’t read the CSS data from sites from a different origin. Say sitea.com loads the css from http://siteb.com/site.css but can not see the rules of the CSS because that may have sensitive information.

Web Storage

Local storage is shared between windows with the same origin and survives when the window is closed. Session storage is only for the current window and is limited to a lifetime of the window.

XMLHttpRequest

Browsers allow sending GET or POST requests to any site and attach required cookies. So, data can be sent anywhere but the response cannot be read by the site if the request was for a different origin.

Getting around SOP

One method to do this is with the PostMessage API which allows one frame or window to talk to another window or frame. Sites can opt-in to this API to remove SOP such that the sender can specify which origin it is sending to and the receiver can check which origin it received the message from and then decide what to do with it.

So, the sender will have something like the following →

1
window.framea.postMessage(message, "http://sitea.com");

The receiver will have something like the following to add listener and check the origin →

1
2
3
4
5
6
7
window.addEventListener('message', function(event) {
		if (event.origin !== 'http://parentsite.com') {
				console.log("Wrong origin! " + event origin);
				return;
		}
		window.rec.innerText = event.data;
}, false);

The other way to do this is using CORS (Cross Origin Resource Sharing).

Resources

PortSwigger: Same-origin policy (SOP)

This post is licensed under CC BY 4.0 by the author.