Same-Origin Policy (SOP)
The Same-Origin Policy (SOP) is a fundamental, mandatory security model enforced by all modern web browsers. It dictates the rules for how a document or script loaded from one origin can interact with resources loaded from another origin.
It is designed to isolate potentially malicious documents and is the single most important security mechanism in the browser's architecture, preventing websites from attacking each other.
Definition of an "Origin"
An "origin" is defined by the unique combination of three distinct components of a URL:
- Protocol (Scheme): The transfer protocol (e.g.,
http://,https://). - Hostname (Domain): The fully qualified domain name (e.g.,
www.example.com). - Port: The port number used for the connection (e.g.,
:80,:443, or an explicitly defined port like:8080).
Example
Consider a scenario where a script on https://bank.com:443 attempts to initiate a cross-origin request to a different domain.
- URL:
https://bank.com/account/Access permitted? Yes: Same scheme (https), domain, and port (443 is default for https). - URL:
https://bank.com:443/transfer/Access permitted? Yes: Same scheme, domain, and port. - URL:
http://bank.com/Access permitted? No: Different scheme (http) and port (80 vs 443). - URL:
https://api.bank.com/Access permitted? No: Different domain (subdomains likeapiare treated as separate origins). - URL:
https://bank.com:8080/Access permitted? No: Different port (8080 vs 443). - URL:
https://malicious-site.com/Access permitted? No: Entirely different domain.
Why SOP is needed?
Without the Same-Origin Policy, the web would have no boundaries. If you logged into your bank in one tab and visited a malicious site in another, that malicious site could use JavaScript to read your bank balance, steal your session tokens, or even read your private messages. SOP is necessary because it ensures that code from one site can never 'spy' on or interfere with data from another.
What SOP Restricts
The Same-Origin Policy is primarily designed to prevent a malicious site from "spying" on your interaction with another site. It places three main restrictions on cross-origin interactions:
- Data Read Access: This is the most critical restriction. A script from
attacker.comcannot read the HTML, cookies, or local storage ofbank.com. It also cannot read the response body of an API request sent tobank.com. - Dom Access: JavaScript on one origin cannot access or manipulate the DOM (Document Object Model) of a page on a different origin. For example, a malicious iframe cannot reach "up" into the parent page to read keystrokes or sensitive data.
- XMLHttpRequest / Fetch: While you can send a request to a different origin, the browser will block the script from seeing the result of that request unless the server explicitly gives permission via Cross-Origin Resource Sharing (CORS) (SOP relaxation).
What SOP doesn't prevent
- SOP mainly blocks cross-origin reads but lets writes like form submissions or link clicks go through. That means an attacker can still trigger state-changing requests (transfer money, change password) even though they can’t see the response. That’s why CSRF protection is needed: it adds a proof that the request came from your app, not just from any page the victim happened to visit.
- You can still embed cross-origin resources (images, scripts, videos), but your JS can’t inspect their contents. There are nuanced exceptions: some properties are writable (e.g.,
iframe.contentWindow.locationcan be set) but not readable, while others are readable but not writable. - SOP doesn’t stop a script from running; any page can execute its own JS. What SOP limits is what that script can access or modify once it’s running (e.g., cross-origin DOM, storage, or responses). To control which scripts/resources can load and run you need to implement Content Security Policy (CSP)
Note
document.domain lets two subdomains relax SOP and talk to each other, but only if both set it to the same parent domain. So marketing.example.com and app.example.com can both set document.domain = 'example.com' and then share access, even though their original origins differ. Browsers used to let you set it to a top-level domain like .com, but that’s now blocked for obvious security reasons.