Maxim Tsoy
Head of R&D at Surfly
Loves the Web
Set-Cookie: riddle=voldemort;Path=/;Domain=london.co.uk;httpOnly;SecureHTTP/1.1 200 OK
Set-Cookie: super_secret=tomato-is-a-fruit!; Path=/cart/; httpOnly; Secure
Content-Length: 0
<meta http-equiv="Set-Cookie" content="name=value">Removed in Chrome in 2018:
Removed in Firefox in 2019:
<meta http-equiv="Set-Cookie" content="name=value">Still works in
getter vs setter
no errors or useful return values
// cookie store jank example from
// https://github.com/WICG/cookie-store/blob/master/explainer.md#reacting-to-session-state-changes
function decode_document_cookie(value) {
// Simplified version of the code at https://github.com/js-cookie/js-cookie.
const cookie_strings = value.split('; ');
const cookies = {};
for (const cookie_string of cookie_strings) {
const index = cookie_string.indexOf('=');
const name = cookie_string.substring(0, index);
const encoded_value = cookie_string.substring(index + 1);
cookies[name] = decodeURIComponent(encoded_value);
}
return cookies;
}
let old_value = null;
function poll(duration_ms, cookie_name, handle_cookie_change) {
const cookies = decode_document_cookie(document.cookie);
const newValue = (cookie_name in cookies) ? cookies[cookie_name] : null;
if (old_value !== new_value) {
handle_cookie_change(new_value);
old_value = new_value;
}
setTimeout(() => {
poll(duration_ms, cookie_name, handle_cookie_change);
}, duration_ms);
}
is synchronous
Cookie: foo=bar; Foo=BarJS:
HTTP:
console.log(document.cookie) // -> "cat=dead"document.cookie = 'cat=alive'console.log(document.cookie) // -> "cat=dead; cat=alive"document.cookie = 'cat=dead; domain=example.com'Set-Cookie: cookiename=cookievalue; Path=/; Domain=cocobolo.com; HttpOnly; Secure
Set-Cookie: cookiename=cookievalue; Path=/; Domain=.cocobolo.com; HttpOnly; Secure
Set-Cookie: cookiename▓=▓cookievalue;▓Path▓=▓/;▓Domain▓=▓cocobolo.com;▓HttpOnly;▓Secure
Set-Cookie: cookiename=cookievalue;Path=/;Domain=cocobolo.com;HttpOnly;Secure
Set-Cookie: cookiename=cookievalue;pATh=/;DoMaIN=cocobolo.com;hTtPOnlY;seCURE
Set-Cookie: cookiename=cookievalue; Path=/; Domain=cocobolo.com; HttpOnly=really; Secure=forsure
Set-Cookie: __Secure-cookiename=cookievalue; Path=/; Domain=cocobolo.com; HttpOnly; Secure
Set-Cookie: cookiename=cookievalue;;;;;;Path=/;;;;;;Domain=cocobolo.com;;;;;HttpOnly;;;;;Secure
Set-Cookie: cookiename=cookievalue; Path=/; Domain=cocobolo.com; HttpOnly; Secure
Set-Cookie: cookiename=cookievalue ; Path=/notthis/; Path=/notthiseither/; Path=/andnoteventhis/; Path=/; Domain=cocobolo.com; HttpOnly; Secure
rarely match the browser behaviour
Safari DevTools: (in recent versions, only "a" will be set)
cookie folding is still supported by many library implementations
Cookies with empty name
Cookies with empty value
Special characters
"=" is valid in the value
whitespaces
Only ASCII is allowed by the spec
Cookie: foo=春节回家路but all major browsers support UTF-8:
Cookie attributes:
Name, Path and Domain define the cookie's identity
These are all different cookies:
Set-Cookie: name=Dwalin; Path=/
Set-Cookie: name=Balin; Path=/profile/
Set-Cookie: name=Kili; Path=/profile/cart/;
Set-Cookie: name=Fili; Path=/profile/cart/change/;
Set-Cookie: name=Dori; Path=/; Domain=.example.com
Set-Cookie: name=Nori; Path=/profile/; Domain=.example.com
Set-Cookie: name=Ori; Path=/profile/cart/; Domain=.example.com
Set-Cookie: name=Oin; Path=/profile/cart/change/; Domain=.example.com
Set-Cookie: name=Gloin; Path=/; Domain=www.example.com
Set-Cookie: name=Bifur; Path=/profile/; Domain=www.example.com
Set-Cookie: name=Bofur; Path=/profile/cart/; Domain=www.example.com
Set-Cookie: name=Bombur; Path=/profile/cart/change/; Domain=www.example.comThe page at https://www.example.com/profile/cart/change/ will receive:
GET / HTTP/1.1
Host: example.com
Cookie: name=Dwalin; name=Balin; name=Kili; name=Fili; name=Dori; name=Nori; name=Ori; name=Oin; name=Gloin; name=Bifur; name=Bofur; name=Bombur
document URL vs cookie URL
https://example.com/healthy/
oatmeal=yes; Path=/healthy/
chocolate=no; Path=/tasty/
history.pushState({}, '', '/tasty/')Change the document URL:
https://example.com/tasty/
oatmeal=yes; Path=/healthy/
chocolate=no; Path=/tasty/
document.cookie == "oatmeal=yes"document.cookie == ???document URL vs cookie URL
https://example.com/healthy/
oatmeal=yes; Path=/healthy/
chocolate=no; Path=/tasty/
history.pushState({}, '', '/tasty/')Change the document URL:
https://example.com/tasty/
oatmeal=yes; Path=/healthy/
chocolate=no; Path=/tasty/
document.cookie == "oatmeal=yes"document.cookie == "oatmeal=yes"document URL vs cookie URL
https://example.com/healthy/
oatmeal=yes; Path=/healthy/
chocolate=no; Path=/tasty/
history.pushState({}, '', '/tasty/')Change the document URL:
https://example.com/tasty/
oatmeal=yes; Path=/healthy/
chocolate=no; Path=/tasty/
document.cookie == "oatmeal=yes"document.cookie == "chocolate=no"
<iframe src="about:blank"></iframe>
<iframe></iframe>
<iframe srcdoc="<p>Inner HTML</p>"></iframe>
<iframe
src="blob:https://example.com/432bd868-f211-417e-aae4-c94892c13945">
</iframe>
<iframe src="file:///C:/Users/muodov/Desktop/secret.html"></iframe>
<iframe src="data:text/html,<p>inner HTML</p>"></iframe>document.cookie = 'foo=bar' inside these iframes?
<!-- Chrome, FF, Safari: inherit parent scope, IE11: empty -->
<iframe src="about:blank"></iframe>
<iframe></iframe>
<iframe srcdoc="<p>Inner HTML</p>"></iframe>
<!-- Firefox: inherit parent scope, Chrome and Safari: empty -->
<iframe
src="blob:https://example.com/432bd868-f211-417e-aae4-c94892c13945">
</iframe>
<!-- Chrome doesn't set cookies, others do -->
<iframe src="file:///C:/Users/muodov/Desktop/secret.html"></iframe>
<!-- Chrome raises DOMException, Firefox and Safari: empty -->
<iframe src="data:text/html,<p>inner HTML</p>"></iframe>document.cookie = 'foo=bar' inside these iframes?
Set-Cookie: coca=cola; Path=/chuck/
• https://example.com/jimmy/ can set cookie on any other path:
Set-Cookie: coca=cola; Domain=.google.com // will be received by maps.google.com and mail.google.com
• https://google.com can set cookies on any subdomain:
Set-Cookie: coca=cola; Path=/chuck/
• https://example.com/jimmy/ can set cookie on any other path:
Set-Cookie: coca=cola; Domain=github.io // will be set for annie.github.io and johnny.github.io
• https://github.io can set cookies on any subdomain:
https://my-evil-app.herokuapp.com
could set cookies on all subdomains of .herokuapp.com:
Set-Cookie: coca=cola; Domain=.herokuapp.com
...affecting all other heroku apps like https://my-innocent-app.herokuapp.com
...unless herokuapp.com is an eTLD in the Public suffix list
(next to .com, .net, .co.uk, etc.)
your-own-space.random-hosting.com ?
• http://example.com
can override Secure cookies set by https://example.com earlier
• httpOnly cookie cannot be overwritten from JS,
but if it was set, server cannot tell whether it is httpOnly or not
Cookie: coca=cola
Cookies might be omitted in "cross-site" requests
https://subdomain.example.co.uk:4433/some/path/
https://subdomain.example.co.uk:4433/some/path/
SOP scope
https://subdomain.example.co.uk:4433/some/path/
SOP scope
Cookie scope
https://subdomain.example.co.uk:4433/some/path/
SOP scope
Cookie scope
"same-site" scope
https://evil.com
https://bank.com/sendmoney/
cross-site
http://example.com
https://example.com
same-site
http://example.com:1111
https://example.com:5555
same-site
https://jimmy.example.com
https://chuck.example.com
same-site