Why websites cannot read each other's data

Modern browsers constantly load resources from many places at once: multiple tabs are open, and pages can host iframes from third-party sites. Without safeguards, a compromised script on any one of those pages could access everything else a user has open. The same-origin policy is the browser feature that prevents this.

It does so by blocking read access to resources that come from a different origin, while still allowing certain resources to be embedded. You can load images, stylesheets, and scripts from a CDN on another origin, but a script from that CDN cannot freely read your page's data, nor can a script on your page read data from that CDN's responses.

Defining an origin

An origin is the combination of a scheme, host, and port. If any one of those differs between two URLs, they are different origins. For instance, http://www.example.com/foo and http://www.example.com/bar share the same origin because the scheme, host, and port (the default port 80 for HTTP) are the same. In contrast, https://www.example.com/bar is cross-origin to the first URL because the scheme changes from http to https.

iframes Cross-origin embedding is usually permitted (depending on the X-Frame-Options directive), but cross-origin reading (such as using JavaScript to access a document in an iframe) isn't.
CSS Cross-origin CSS can be embedded using a <link> element or an @import in a CSS file. The correct Content-Type header may be required.
forms Cross-origin URLs can be used as the action attribute value of form elements. A web application can write form data to a cross-origin destination.
images Embedding cross-origin images is permitted. However, reading cross-origin image data (such as retrieving binary data from a cross-origin image using JavaScript) is blocked.
multimedia Cross-origin video and audio can be embedded using <video> and <audio> elements.
script Cross-origin scripts can be embedded; however, access to certain APIs (such as cross-origin fetch requests) might be blocked.

Cross-origin restrictions

Although some tags can embed cross-origin resources, that allowance is a legacy of the early web and can create risks. A notable exploit is clickjacking: an attacker loads your site inside an invisible iframe, overlays transparent buttons that point elsewhere, and lures a user into performing actions meant for one website while sending data to another.

To stop other origins from framing your site, send a header that declares who may embed it. A Content Security Policy with the frame-ancestors directive is the the modern approach. The older X-Frame-Options header can also be used; the list of its possible values is documented on MDN.

The same-origin policy is an important part of how browsers keep the web secure. However, legitimate applications often need to share data across origins. That is where Cross-Origin Resource Sharing (CORS) enters the picture: it is the mechanism for telling the browser which trusted origins may read a resource you serve.