When browsing the web, it can often feel like your privacy is being constantly invaded and your data misused; in the most by companies spying on you to advertise things you don’t really need.
As the Moneyed app enables users to view their financial data, it’s vital that privacy and security are built into the core of our tech. One security consideration is cookies: if an attacker stole your session identifier, they could pretend to be you, and potentially view your data.
Below is a list of some of the cookie-related procedures we follow at Moneyed. To keep everyone’s data safe, other companies should be doing the same with their cookies (but, as the title suggests, they probably aren’t).
The session identifier could be stored in a cookie, sessionStorage, or localStorage. Given that the session identifier is only required by the server, access should be restricted to it; this is possible to do with cookies (see number 4), but not possible with sessionStorage and localStorage.
Strictly necessary cookies do not require consent from the user[1]; this avoids the need for an annoying cookie permission popup and signals to the user that you care about their privacy.
The secure attribute requires that the browser only accepts the cookie and only shares the cookie if the site is secure, e.g. served over HTTPS, making it harder for a man-in-the-middle attacker to steal the cookie[2, 3].
The HttpOnly attribute requires that the browser only share the cookie with the server (via HTTP requests) and specifically prevents scripts running in the browser from accessing the cookie; this makes it harder for a cross site scripting (XSS) attacker to steal the cookie[2, 4].
The path attribute specifies which URL paths the cookie is shared with. Setting the path attribute to '/' means the cookie is shared with any path on the domain[2]; this is best practice as most security measures are based on the origin (rather than path).
The domain attribute specifies which URL domains the cookie is shared with. Not including/setting the domain activates the host-only-flag, ensuring that the cookie is only shared with the host that set it; this is preferable to explicitly setting the domain as it excludes subdomains.
The SameSite attribute controls when a cookie is shared with cross origin requests. Strict should be used in preference as it prevents any sharing, whereas Lax allows for top level navigation i.e. when a user follows a link from an external site.
Adding __Host-
as a prefix to the cookie name requires that the Secure attribute is set, the Path attribute is set to '/', and the domain attribute is not set; this acts as a failsafe ensuring that the cookie cannot exist without these attributes.
By not setting max-age or expires the cookie becomes a session cookie; this ensures that the cookie is deleted when the user’s session ends. The alternative is needing to remember to delete the cookie, or predict the perfect time in the future to schedule a deletion.
When a user logs out, they expect their session to end and therefore that the cookie has been deleted. Cookie deletion is usually achieved by setting a cookie that expires immediately. For this to work the cookie must have the correct combination of attributes e.g. deleting a `__Host-` prefixed cookie requires the Secure, Path, and domain attributes to have the correct values.
Our session cookies incorporate all of the best practices outlined above, the exact header is the one at the top of the page, Set-Cookie: __Host-[name]=[value]; Secure; HttpOnly; Path=/; SameSite=Strict
.
The following open source changes have been sponsored by Moneyed to help secure cookies for all,
[1] Strictly necessary cookies, GDPR https://gdpr.eu/cookies/
[2] MDN Web docs Using HTTP cookies
[3] MDN Web docs Man-in-the-middle attacker
[4] MDN Web docs XSS
[5] RFC6265 draft