In the modern version of Chrome, regardless of the underlying OS, you can overwrite cookies with HttpOnly set.
If you’ve been around long enough in web security or perhaps dug deep into the literature on web attacks, you might know this as ‘cookie jar overflow’, ‘cookie overflow’ (my favorite because it sounds delicious), or ‘cookie forcing’, because it’s really not a new attack.
However, in the broader community it’s still relatively unknown, to the point where OWASP’s own page on HttpOnly still claims that it’s safe against both reads and writes. And most top articles on cookie protections will still mention HttpOnly as write-protection.
But it’s wrong. Oh, oh so wrong.
Hold onto your head tightly, because otherwise it might explode from the complexity of the attack.
Here’s a piece of code that lets you overwrite any HttpOnly cookie in Chrome (on any OS and device):
Hope you’re still alive and made it through that wall of code.
The above code assumes ‘victimcookie’ is the cookie you want to overwrite. It works because Chrome has a limited capacity for cookies in its cookie jar. Once you go over this amount, it starts deleting old ones… including HttpOnly cookies.
So, why is this a big deal?
There are two scenarios where this is incredibly juicy for attackers.
Lots of applications have session cookies, and lots of applications will re-use whatever value you happen to already have in your session cookie (this is super common), so by an attacker injecting a XSS payload snippet with something like:
The attacker sets the victim’s session id to
totallysecure, which the server happily accepts when the victim logs in.
Then, by the attacker knowing this ‘secret’ value, the attacker can log in as the end-user by simply setting their own browsers' session_id to the same value.
Manipulate application state
Some applications control the state of the application through cookies.
You might imagine a banking application that once you submit who you send the money to, the server instructs your browser, “hold onto the recipient’s bank id number for me” by setting it as a cookie for use in later steps. To be safe, the bank sets it as HttpOnly so attackers can not modify it.
Because it’s writable, if you know how to, the attacker injects an XSS payload into the page and overwrites the recipient bank id with their own to steal some money.
We’re all doomed.
How do we mitigate against this?
Okay, but really, how do we get around this, assuming we’re aware of the problem?
Off the top of my head, you have three options:
Use something to provide integrity on top of cookies
You could, for instance, use Json Web Tokens (JWT) containing your data of choice signed by your server and validate them before each (!) use.
(The above JWT token contains
"session_id": "banana" in its payload)
You could also manually attach an HMAC to whatever values you need ingegrity checked together by some delimiter and verify on the server-side that the HMAC is the same as you would expect.
Here, the HMAC is a SHA1 hash of the session id
123123123banana with the secret key
hunter2 (please pick a better key) that the server can use to re-compute the associated HMAC and determine the value hasn’t been modified.
Without the secret key, the attacker can not tamper with the message.
Make it so it doesn’t matter if they get tampered with
In the session fixation case, the most robust solution is to discard the user’s value for the session id cookie and provide a new one regardless if they already have one or not.
If you always get a new one, it doesn’t matter if your old one’s broken.
I’m not even kidding.
That said, this adds a significant amount of engineering work since there’s no easy way to e.g. add headers to HTML form requests, and pros/cons should be weighed heavily.
Thanks for reading!