LEARNING OBJECTIVES โต
- Define an origin using the RFC 6454
<scheme, host, port>tuple algorithm. - Differentiate between cross-origin writes, cross-origin embeds, and cross-origin reads.
- Understand how the Same-Origin Policy isolates the DOM,
localStorage,sessionStorage,IndexedDB, andCookies. - Identify historical bypass attempts and modern strict boundary enforcement in user agents.
๐ The Mental Model & Story (Intuitive Foundation)
Imagine living in a high-density, multi-tenant apartment building. Each tenant possesses their own private apartment with a unique key.
- Your apartment number is Suite 401, Building B, HTTPS Towers (
https://bank.example.com:443). - Down the hallway lives another tenant in Suite 401, Building B, HTTP Towers (
http://bank.example.com:80). - Across the street lives a third tenant in Suite 401, Building C, HTTPS Towers (
https://attacker.example.com:443).
+-----------------------------------------------------------------------------------+
| THE BROWSER APARTMENT BUILDING |
+-----------------------------------------------------------------------------------+
| [Apartment A: https://bank.com:443] | [Apartment B: https://bank.com:8443] |
| - Private DOM (Bank Balance) | - Separate Memory Space |
| - Auth Cookies & LocalStorage | - Isolated IndexedDB |
| ----------------------------------- | ------------------------------------ |
| * Tenant A CANNOT unlock Tenant B's door, even though domain name matches! |
+-----------------------------------------------------------------------------------+
| [Apartment C: https://attacker.com:443] |
| - Can deliver mail through the mail slot (Cross-Origin Write: POST /transfer) |
| - CANNOT open the door and read financial papers (Cross-Origin Read: Blocked!) |
+-----------------------------------------------------------------------------------+
The building's strict security guard is the Same-Origin Policy (SOP). The guard enforces one foundational rule: Tenants may never enter another tenant's room, read their confidential documents, or rummage through their closets without explicit cryptographic permission.
Introduced by Netscape Navigator 2.0 in 1995 to protect script access to document properties across frames, the Same-Origin Policy is the cornerstone of web application security. Without SOP, visiting https://evil-site.com in one browser tab would allow an attacker's script to reach across the browser runtime, inspect https://my-bank.com open in another tab, read your private account balances from its DOM, extract your session cookies, and initiate unauthorized wire transfers.
Technical Deep Dive & Specifications
The Origin Definition (RFC 6454)
Under RFC 6454 (The Web Origin Concept), an origin is defined strictly as the tuple of three components:
$$\text{Origin} = \langle \text{Scheme}, \text{Host}, \text{Port} \rangle$$
Two URLs share the same origin if and only if all three components are identical.
URL: https://sub.example.com:443/app/dashboard?user=123#profile
\___/ \_____________/ \_/ \_________________________/
Scheme Host Port Path & Query
| |
+---- THE ORIGIN TUPLE ----+
Origin Comparison Matrix
Let the reference origin be: https://www.example.com:443/dir/page.html (Default HTTPS port 443).
| Candidate URL | Same Origin? | Reason for Decision |
|---|---|---|
https://www.example.com/dir/other.html |
โ YES | Exact match: same scheme (https), host (www.example.com), and implicit port (443). Path differences are ignored by SOP. |
https://www.example.com/dir/inner/page2.html |
โ YES | Exact match: same scheme, host, and port. |
http://www.example.com/dir/page.html |
โ NO | Scheme mismatch: http (port 80) vs https (port 443). |
https://www.example.com:8080/dir/page.html |
โ NO | Port mismatch: 8080 vs 443. |
https://api.example.com/dir/page.html |
โ NO | Host mismatch: api.example.com is a distinct subdomain from www.example.com. |
https://example.com/dir/page.html |
โ NO | Host mismatch: apex domain example.com vs subdomain www.example.com. |
https://v2.www.example.com/dir/page.html |
โ NO | Host mismatch: different subdomain hierarchy. |
What SOP Restricts vs What It Allows
A common point of confusion is believing that SOP blocks all cross-origin activity. The browser handles cross-origin interactions across three distinct categories:
+-----------------------------------------------------------------------------------+
| CROSS-ORIGIN INTERACTION SPECTRUM |
+-----------------------------------------------------------------------------------+
| 1. WRITES (Normally Allowed) |
| - Hyperlink navigations (<a href="...">) |
| - Form submissions (<form action="https://other.com" method="POST">) |
| - Redirects (301, 302, 307) |
| |
| 2. EMBEDS (Normally Allowed) |
| - Scripts: <script src="https://other.com/lib.js"></script> |
| - Styles: <link rel="stylesheet" href="https://other.com/style.css"> |
| - Images: <img src="https://other.com/photo.jpg" alt="..."> |
| - Media: <video src="https://other.com/clip.mp4"></video> |
| - Frames: <iframe src="https://other.com/embed.html"></iframe> |
| |
| 3. READS (Strictly Blocked by Default!) |
| - XMLHttpRequest / fetch() response text & headers |
| - Inspecting iframe.contentDocument / DOM nodes |
| - Canvas 2D pixel extraction (getImageData, toDataURL) |
| - Web Storage: localStorage, sessionStorage, IndexedDB |
| - Reading document.cookie of another origin |
+-----------------------------------------------------------------------------------+
Storage and DOM Isolation Boundaries
- DOM Tree Access: If origin
Aembeds originBvia<iframe id="myFrame" src="https://b.com">,A's scripts can executemyFrame.contentWindow, but accessingmyFrame.contentDocumentormyFrame.contentWindow.documentimmediately throws aDOMException: Blocked a frame with origin "https://a.com" from accessing a cross-origin frame. - Client Storage:
window.localStorageandwindow.sessionStorageare sandboxed strictly per<scheme, host, port>.IndexedDBdatabases are isolated per origin.CacheStorage(Service Worker cache) is partitioned per origin.
- Cookie Partitioning: Cookies historically adhered to a looser domain/path scoping rather than a strict origin tuple. For instance,
example.comcould set a cookie readable bysub.example.com. Modern browsers enforceSameSiteattributes and CHIPS (Cookies Having Independent Partitioned State) to align cookies closer to origin boundaries.
๐ป Interactive Code Playground
Starter Code
Line-by-Line Code Breakdown
- Lines 31โ32: Evaluates
window.location.origin, displaying the exact<scheme, host, port>of the running client page. - Line 35: References an
<iframe>loadinghttps://example.com. Even though the iframe successfully renders pixels on the screen (cross-origin embedding is permitted), its internal memory structure is sandboxed. - Line 41: Attempts to dereference
iframe.contentDocument. When the origin of the outer frame does not matchhttps://example.com, the browser's security boundary intercepts the call and raises aSecurityError / DOMException. - Line 53: Dispatches a standard
fetch('https://example.com/'). Becauseexample.comdoes not provide CORS headers permitting reading from our origin, the promise rejects with aTypeError: Failed to fetch.
Expected Browser Render Output
๐ Same-Origin Policy (SOP) Live Inspector
Current Execution Origin: https://my-dev-host.local:3000
+-------------------------------------------------------------+
| [Embedded Frame: Example Domain (example.com) rendered here] |
+-------------------------------------------------------------+
[ Inspect iFrame DOM ] [ Fetch Cross-Origin Data ]
[ Output Box - Red Background ]:
๐ SOP Blocked DOM Access:
DOMException: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "https://my-dev-host.local:3000" from accessing a cross-origin frame.๐๏ธ Hands-On Exercise
๐ฏ The Challenge: Build an Origin Equivalence & Policy Rule Engine
Instructions:
- Implement a JavaScript function
isSameOrigin(urlA, urlB)that parses two URL strings and returnstrueif and only if their<scheme, host, port>tuples match identically according to RFC 6454. - Handle implicit default ports (
http= 80,https= 443). - Implement
evaluateAction(sourceUrl, targetUrl, actionType)whereactionTypeis'DOM_READ','FORM_POST', or'SCRIPT_EMBED'. The function must return whether SOP permits the action by default without CORS.
๐ Starter Code Sandbox
โ ๏ธ Common Pitfalls
- Assuming Subdomains Share an Origin:
app.example.comandapi.example.comare completely different origins. Scripts running onapp.example.comcannot directly read objects onapi.example.comvia DOM access or standard fetch without CORS. - Assuming SOP Prevents Form Submissions (CSRF): SOP does not stop a malicious page from submitting a hidden
<form action="https://bank.com/transfer" method="POST">containing ambient credentials (cookies). SOP only prevents the attacker from reading the server's response. CSRF tokens orSameSitecookies are required to prevent unauthorized writes. - Relying on Legacy
document.domainRelaxation: Settingdocument.domain = "example.com"to allow communication betweensub1.example.comandsub2.example.comhas been deprecated by web standards and disabled by default in modern browsers (Chrome 115+) due to fundamental security weaknesses. Usewindow.postMessage()instead.
๐ก Pro Tips
- Leverage
window.postMessage()for Cross-Origin Communication: When multiple origins need to exchange data between frames or tabs, use structured messaging with strict target origin validation:// Sender: targetWindow.postMessage({ type: 'AUTH_SUCCESS', token }, 'https://trusted-receiver.com'); // Receiver: window.addEventListener('message', (event) => { if (event.origin !== 'https://trusted-sender.com') return; // Strict boundary check handleAuth(event.data); }); - Treat Port Numbers as Hard Security Boundaries: In local development environments,
http://localhost:3000(React) andhttp://localhost:8080(API server) are distinct origins. Configure reverse proxies or CORS policies during development rather than disabling browser security flags.
๐ Key Takeaways
- An origin is strictly defined by the RFC 6454 tuple:
<Scheme, Host, Port>. If any component differs, the origin is distinct. - The Same-Origin Policy (SOP) is the foundational security boundary implemented by all compliant web browsers.
- SOP blocks cross-origin reading (network responses, DOM trees, client storage like
localStorage/IndexedDB). - SOP historically allows cross-origin writes (links, redirects, form POSTs) and cross-origin embeds (
<script>,<img>,<iframe>). - Safe cross-origin communication between frames must be achieved via
window.postMessage()with rigorousevent.originverification. - --