Lecture 03
Lecture 03
1 Feross Aboukhadijeh
Admin
• Assignment 0 is due Wednesday, September 29 at 5:00pm
2 Feross Aboukhadijeh
What should be allowed?
• Should site A be able to link to site B?
• Should site A be able to embed site B?
• Should site A be able to embed site B and modify its contents?
• Should site A be able to submit a form to site B?
• Should site A be able to embed images from site B?
• Should site A be able to embed scripts from site B?
• Should site A be able to read data from site B?
3 Feross Aboukhadijeh
Same Origin Policy
• This is the fundamental security model of the web
• If you remember one thing from this class, this is it:
• Two pages from different sources should not be allowed to
interfere with each other
4 Feross Aboukhadijeh
The web is an operating system
• An origin is analogous to an OS process
• The web browser itself is analogous to an OS kernel
• Sites rely on the browser to enforce all the system's security rules
• If there's a bug in the browser itself then all these rules go out
the window (just like in an OS)
5 Feross Aboukhadijeh
The basic rule
• Given two separate JavaScript execution contexts, one should be
able to access the other only if the protocols, hostnames, and port
numbers associated with their host documents match exactly.
• This "protocol-host-port tuple" is called an "origin".
6 Feross Aboukhadijeh
7 Feross Aboukhadijeh
8 Feross Aboukhadijeh
Same origin policy
function isSameOrigin (url1, url2) {
return url1.protocol === url2.protocol &&
url1.hostname === url2.hostname &&
url1.port === url2.port
}
9 Feross Aboukhadijeh
What should be allowed?
• Where does one document begin and another end?
• How much interaction should be allowed between non-cooperating
origins?
• Which actions should be subject to security checks?
10 Feross Aboukhadijeh
Demo: Same origin policy
11 Feross Aboukhadijeh
Demo: Same origin policy
From https://web.stanford.edu/class/cs253/:
// Even this!
let i = 0
const imgs = iframe.contentDocument.body.querySelectorAll('img')
setInterval(() => {
imgs.forEach(img => img.style.transform = `rotate(${i}deg)`)
i += 1
}, 50)
12 Feross Aboukhadijeh
Demo: Same origin policy (pt 2)
From https://web.stanford.edu/class/cs253/:
// Is this allowed?
document.body.append(iframe) // Allowed!
// Is this allowed?
iframe.contentDocument.body.style.backgroundColor = 'red' // Not allowed!
// Is this allowed?
iframe.src = 'https://example.com' // Allowed! Surprised?
13 Feross Aboukhadijeh
Demo: Is cross-origin fetch allowed?
From https://web.stanford.edu/class/cs253/:
const res = await fetch('https://axess.stanford.edu')
const data = await res.body.text()
console.log(data)
• No! Would be a huge violation of Same Origin Policy.
• Any site in the world could read your grades if you're logged into
Axess in another tab!
14 Feross Aboukhadijeh
Same origin or not?
• https://example.com/a/ → https://example.com/b/
• Yes!
• https://example.com/a/ → https://www.example.com/b/
• No! Hostname mismatch!
• https://example.com/ → http://example.com/
• No! Protocol mismatch!
• https://example.com/ → https://example.com:81/
• No! Port mismatch!
• https://example.com/ → https://example.com:80/
• Yes!
15 Feross Aboukhadijeh
Problems
• Sometimes policy is too narrow: Difficult to get login.stanford.edu
and axess.stanford.edu to exchange data.
• Sometimes policy is too broad: No way to isolate https://
web.stanford.edu/class/cs106a/ from https://web.stanford.edu/
class/cs253/ ...much to CS 106A staff's disappointment!
• Policy is not enforced for certain web features!
• You need to know which ones!
16 Feross Aboukhadijeh
document.domain
• Idea: Need a way around Same Origin Policy to allow two different
origins to communicate
• Two cooperating sites can agree that for the purpose of Same Origin
Policy checks, they want to be considered equivalent.
• Sites must share a common top-level domain.
• Example: both login.stanford.edu and axess.stanford.edu may
perform the following assignment:
document.domain = 'stanford.edu'
17 Feross Aboukhadijeh
Any subdomain can join the
document.domain party!
• So, if axess.stanford.edu and attacker.stanford.edu both run:
document.domain = 'stanford.edu'
• Then attacker.stanford.edu can access content on
axess.stanford.edu! Bad!
18 Feross Aboukhadijeh
Demo:
document.domain on
crypto.stanford.edu
19 Feross Aboukhadijeh
Demo: document.domain on
crypto.stanford.edu
From https://crypto.stanford.edu:
document.domain = 'stanford.edu'
From https://web.stanford.edu/class/cs253/:
document.domain = 'stanford.edu'
// Is this allowed?
iframe.contentDocument.body.style.backgroundColor = 'red' // Allowed!
20 Feross Aboukhadijeh
document.domain requires opt-in
• Both origins must explicitly opt-in to this feature
• So, if attacker.stanford.edu runs:
document.domain = 'stanford.edu'
document.domain = 'stanford.edu'
21 Feross Aboukhadijeh
Originating URL document.domain Accessed URL document.domain Allowed?
22 Feross Aboukhadijeh
Originating URL document.domain Accessed URL document.domain Allowed?
23 Feross Aboukhadijeh
document.domain is a bad idea
• In order for login.stanford.edu and axess.stanford.edu to
communicate, they must set:
document.domain = 'stanford.edu'
• This allows anyone on stanford.edu to join the party
24 Feross Aboukhadijeh
Send messages from a parent page
to a child iframe
• Idea: Need a way around Same Origin Policy to allow two different
origins to communicate
• What if we encoded data in URL fragment identifiers?
• Gap in same origin policy!
• Parent is allowed to navigate child iframes
• Child can poll for changes to the fragment identifier
25 Feross Aboukhadijeh
26 Feross Aboukhadijeh
Demo: Fragment identifier cross-
origin communication
27 Feross Aboukhadijeh
Demo: Fragment identifier cross-origin
communication
site-a.com:
<h1>Parent: http://site-a.com:8000</h1>
<input name='val' />
<br /><br />
<iframe src='http://site-b.com:8001' width='100%' height='400px'></iframe>
<script>
const input = document.querySelector('input')
const iframe = document.querySelector('iframe')
input.addEventListener('input', () => {
iframe.src = `http://site-b.com:8001#${encodeURIComponent(input.value)}`
})
</script>
site-b.com:
<h1>Child: http://site-b.com:8001</h1>
<div></div>
<script>
const div = document.querySelector('div')
setInterval(() => {
div.textContent = decodeURIComponent(window.location.hash).slice(1)
}, 100)
</script>
28 Feross Aboukhadijeh
The postMessage API
• Secure cross-origin communications between cooperating origins
• Send strings and arbitrarily complicated data cross-origin
• Useful features:
• "Structured clone" algorithm used for complicated objects.
Handles cycles. Can't handle object instances, functions, DOM
nodes.
• "Transferrable objects" allows transferring ownership of an object.
It becomes unusable (neutered) in the context it was sent from.
29 Feross Aboukhadijeh
Demo: postMessage cross-origin communication
site-a.com:
<h1>Parent: http://site-a.com:8000</h1>
<input name='val' />
<br /><br />
<iframe src='http://site-b.com:8001' width='100%' height='400px'></iframe>
<script>
const input = document.querySelector('input')
const iframe = document.querySelector('iframe')
input.addEventListener('input', () => {
iframe.contentWindow.postMessage(input.value, 'http://site-b.com:8001')
})
</script>
site-b.com:
<h1>Child: http://site-b.com:8001</h1>
<div></div>
<script>
const div = document.querySelector('div')
window.addEventListener('message', event => {
if (event.origin !== 'http://site-a.com:8000') return
div.textContent = event.data
})
</script>
30 Feross Aboukhadijeh
More realistic example
• axess.stanford.edu wants to display name of logged in user, so it registers a listener for messages:
31 Feross Aboukhadijeh
32 Feross Aboukhadijeh
33 Feross Aboukhadijeh
34 Feross Aboukhadijeh
35 Feross Aboukhadijeh
36 Feross Aboukhadijeh
37 Feross Aboukhadijeh
Need to validate destination of
messages!
• If an attacker embeds login.stanford.edu, they can listen to it's
message which reveals the name of the logged in user!
• Solution: login.stanford.edu should specify intended recipient
origin. Browser will enforce this.
const data = { name: 'Feross Aboukhadijeh' }
window.parent.postMessage(data, 'https://axess.stanford.edu')
38 Feross Aboukhadijeh
39 Feross Aboukhadijeh
40 Feross Aboukhadijeh
41 Feross Aboukhadijeh
42 Feross Aboukhadijeh
43 Feross Aboukhadijeh
44 Feross Aboukhadijeh
Need to validate source of messages!
• If an attacker has a reference to a axess.stanford.edu window (by
e.g. embedding it in an iframe), they can send a message to it to trick
it!
• Solution: axess.stanford.edu should verify source origin of message!
window.addEventListener('message', event => {
if (event.origin !== 'https://login.stanford.edu') return
setCurrentUser(event.data.name)
})
45 Feross Aboukhadijeh
Integrity of postMessage
• Sender must specify origin which is permitted to receive message
• In case the URL of the target window has changed
• Recipient must validate the identity of the sender
• In case some other window is sending the message
• Remember: Always specify intended recipient or expected sender!
46 Feross Aboukhadijeh
Same origin policy exceptions
• Summary: There are explicit opt-out mechanisms like
document.domain, fragment identifier communication, and the
postMessage API
• There are also automatic exceptions
• Need to be aware of these!
• Source of many security issues!
47 Feross Aboukhadijeh
Same origin policy - automatic
exceptions
• Which of these requests from example.com are allowed?
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<link rel='stylesheet' href='https://other1.com/style.css' />
</head>
<body>
<img src='https://other2.com/image.png' />
<script src='https://other3.com/script.js'></script>
</body>
</html>
48 Feross Aboukhadijeh
Same origin policy exceptions
• Answer: All of them!
• Embedded static resources can come from another origin
• Images (e.g. hotlinking to memes)
• Scripts (e.g. Facebook like button, ads, tracking scripts)
• Styles (e.g. Google Fonts)
• Why was it designed this way?
49 Feross Aboukhadijeh
END
50 Feross Aboukhadijeh