Author Archives: Simon Waters

Use Cookies like it is 2018

TL;DR set all the cookie flags you can, use strict transport security with “IncludeSubDomains”, don’t run with scissors.

Having started on the route into Bug Bounty hunting it is kind of amusing to me that cookie weaknesses are often ruled out of scope because they are discover-able with trivial automated scans when the sites involved still have cookies that are open to abuse.

Cookies and least privilege

The first thing to realize with using cookies is the privilege model is completely messed up.

The easiest example is cookie flags. Each cookie can be flagged as “secure”, “httponly”, “same-site”, each of these restrict how the cookie is read (but not necessarily how it is set!). Secure cookies can only be read by servers with a certificate; httpOnly can’t be read by JavaScript; Same-Site restricts whether a cookie is included in requests initiated from third party sites (e.g. Cross Site Request Forgery). Clearly the most secure cookie has all these flags set. A least privilege model should set all these flags and remove those required for functionality, but that is not what we see in practice.

In practice it is not uncommon to see only the session cookie with the secure flag, the other cookies are often easily stolen (or watched!), and can reveal all sorts of details of a user’s activity, sometimes including security sensitive information like CSRF tokens which can further the technical attack against the user, or personally identifying information being entered into a service like delivery addresses which can be used for social engineering (“Hi I just entered order XYZ for delivery to my home address ‘123 Acacia Avenue’ by mistake, can you deliver it to my girlfiend’s address?”).

Since browsers also typically preserve session cookies between restarts, if a cookie doesn’t have an explicit expiry (or max-age) attribute it won’t expire. Another case of the default doing the wrong thing even when the standards said the right thing once.

Thus the work falls to developers to explicitly set all of their cookies attributes. Adding cookies to an application is thus harder work than it should be and error prone.

RFC 6265 and sub-domains

Cookies get sent to sub-domains, this matters even if you don’t have sub-domains.

Even if you read and followed RFC 6265 and are sure your cookie shouldn’t go to sub-domains, Internet Explorer never implemented RFC 6265 so some percentage (about 7.5% currently) of your user’s cookies are still going to sub-domains.

This matters because users often trust the DNS (either the wireless access point gives them DNS servers via DHCP, or they use well known DNS servers like Google’s without protecting the traffic against manipulation), allowing attackers to add non-existent sub-domains (e.g. nonsuch.example.com), which they can use to read (and track) any cookie that isn’t sufficiently protected in the parent domain (example.com).

In an ideal world users would use DNS from a trusted source such as DNS over TLS in the latest Android, or DNS over HTTPS from Cloudflare, or fetched over a company VPN, but then in an ideal world users wouldn’t use IE 11, and wouldn’t click through security warnings; we engineer for the world we have, not the one we want.

What is “sufficiently protected” against rogue access points?

Setting the “Secure flag” is a good start, whilst sometimes a rogue access point owner might still be able to set a malicious cookie, he can’t read a cookie flagged secure unless the user clicks through a security warning.

[Recent browser changes make it harder to set a cookie with a secure flag over HTTP, if the cookie already exists. This stops a whole lot of cookie forcing attacks, but only if your browser supports this behaviour.]

Alas users are likely to click through security warnings because for a long time this was how you made Wireless Access Point work at less enlightened cafes. hotels and airports.

You can stop the setting of a malicious cookie by using strict transport security.

Strict transport security when used with the “includeSubDomains” option would also prevent the easy creation of malicious sub-domains (since the attacker would need a valid certificate), better yet strict transport security removes the user’s ability to trust an invalid certificate for your domain, so no clicking through security warnings.

Thus the minimum practical solution for cookie security against rogue access points is “secure flag”+”strict transport security including sub-domains”. This works in Internet Explorer 11, and the use of the long established “secure” flags means that even minority browsers that lack strict transport security like Android browser, or Internet Explorer Mobile, still need the user to click through a security warning before the cookie’s contents are compromised.

Is a cookie still the right place?

Whilst the httpOnly flags provides cookies with some interesting security properties and may make them suitable for storing session identifiers and cross site request forgery prevention tokens, user data is almost certainly better stored in web storage. Web storage has done the right thing in respecting scheme (by default) since Internet Explorer 8, and you are less likely to accidentally trip a storage limit, or otherwise falls foul of security restrictions.