Tuesday, May 31, 2016

Web Storage: the lesser evil for session tokens

I was recently asked whether it was safe to store session tokens using Web Storage (sessionStorage/localStorage) instead of cookies. Upon googling this I found the top results nearly all assert that web storage is highly insecure relative to cookies, and therefore not suitable for session tokens. For the sake of transparency, I've decided to publicly document the rationale that lead me to the opposite conclusion.

The core argument used against Web Storage says because Web Storage doesn't support cookie-specific features like the Secure flag and the HttpOnly flag, it's easier for attackers to steal it. The path attribute is also cited. I'll take a look at each of these features and try to examine the history of why they were implemented, what purpose they serve and whether they really make cookies the best choice for session tokens.

The Secure Flag

The secure flag is quite important for cookies, and outright irrelevant for web storage. Web Storage adheres to the Same Origin Policy, which isolates data based on an origin consisting of a protocol and a domain name. Cookies need the secure flag because they don't properly adhere to the Same Origin Policy - cookies set on https://example.com will be transmitted to and accessible via http://example.com by default. Conversely, a value stored in localStorage on https://example.com will be completely inaccessible to http://example.com because the protocols are different.

In other words, cookies are insecure by default, and the secure flag is simply a bodge to make them as resilient to MITM attacks as Web Storage. Web Storage used over HTTPS effectively has the secure flag by default. Further information on related nuances in the Same Origin Policy can be found in The Tangled Web by Michal Zalewski.

The Path Attribute

The path attribute is widely known to be pretty much useless for security. It's another example of where cookies are out of sync with the Same Origin Policy - paths are not considered part of an origin so there's no security boundary between them. The only way to isolate two applications from each other at the application layer is to place them on separate origins.

The HttpOnly Flag

The HttpOnly flag is an almost useless XSS mitigation. It was invented back in 2002 to prevent XSS being used to steal session tokens. At the time, stealing cookies may have been the most popular attack vector - it was four years later that CSRF was described as the sleeping giant.

Today, I think any competent attacker will exploit XSS using a custom CSRF payload or drop a BeEF hook. Session token stealing attacks introduce a time-delay and environment shift that makes them impractical and error prone in comparison - see Why HttpOnly Won't Protect You for more background on why. This means that if an attacker is proficient, HttpOnly won't even slow them down. It's like a WAF that's so ineffective attackers don't even notice it exists.

The only instance I've seen where HttpOnly was a significant security boundary is on bugzilla.mozilla.org. Untrusted HTML attachments are served from a subdomain which has access to the parent domain's session cookies thanks to cookies' not-quite-same-origin-policy. Ultimately as with the secure flag, the HttpOnly flag is only really required to make cookies as secure as web storage.

Differences that Matter

One major difference between the two options is that unlike cookies, web browsers don't automatically attach the contents of web storage to HTTP requests - you need to write JavaScript to attach the session token to a HTTP header. This actually conveys a huge security benefit, because it means the session tokens don't act as an ambient authority. This makes entire classes of exploits irrelevant. Browsers' behaviour of automatically attaching cookies to cross-domain requests is what enables attacks like CSRF and cross-origin timing attacks. There's a specification for yet another another cookie attribute to fix this very problem in development at the moment but for now to get this property, your best bet is Web Storage.

Meanwhile, the unhealthy state of the cookie protocol leads to crazy situations where the cookie header can contain a blend of trusted and untrusted data. This is something the ill-conceived double-submit CSRF defence fell foul of. The solution for this is yet another cookie attribute: Origin.

Unlike cookies, web storage doesn't support automatic expiry. The security impact of this is minimal as expiry of session tokens should be done server-side, but it is something to watch out for. Another distinction is that sessionStorage will expire when you close the tab rather than when you close the browser, which may be awesome or inconvenient depending on your use case. Also, Safari disables Web Storage in private browsing mode, which isn't very helpful.

This post is intended to argue that Web Storage is often a viable and secure alternative to cookies. Web Storage isn't ideal for session token storage in every situation - retrofitting it to a non single-page application may add a significant request overhead, Safari disables Web Storage in private browsing mode, and it's insecure in Internet Explorer 8. Likewise, if you do use cookies please use both Secure and HttpOnly.


At first glance it looks like cookies have more security features, but they're ultimately patches over a poor core design. For an in depth assessment of cookies, check out HTTP cookies, or how not to design protocols. Web Storage offers an alternative that, if not secure by default, is less insecure by default.

 - @albinowax


Christian Jensen said...

I concur.

I would love to see a "Best Security Practices" for Web Storage - something that would have an apples to apples with cookies complete with JS examples.

Dan said...

There is an issue with local storage and private browsing in some browsers i believe.. It might not be a massive problem for majority of situations, but its always made me question using it.

Rodrigo said...


Bruce Wang said...

Back in 2013 when we started developing our single page apps, one of the rules we had was like "cookies must die, c'mon it's 2013". We basically agreed that web storage is the only way to mitigate CSRF problem which is indeed a sleeping security threat waiting to happen. XSS would still be possible with or without cookies, you just got to be careful with any user inputs. Hence, I'm completely onboard with your idea.

I should probably blog about it one of these days. We even had a working Single Sign On + Out employing web storage as the session storage plus notifier when user logged out. Safari doesn't quite work as we wanted it to be. Since Safari 7, Apple has been quite cautious to let 3rd party collecting cross domain user data for Big G advertiser. They initially restricted cookies only, and then with Safari 7, it included web storage as well. Other than that, we are extremely happy to employ web storage as the session storage, and let javascript to be the judge to whom it should pass the authentication data.

James Kettle said...

@Dan Good point, Safari disables web storage in private browsing mode, which is definitely awkward if that's a likely use case. I've added a reference to this in the post.

Cornerpirate said...

Pretty decent conclusions *yoink*.

Nunya Bidness said...

@Dan... Thank you thank you thank you... Someone finally speaks the truth. I am sick and tired of the plethora of web security lore.

Stefan Orri said...

It's worth mentioning that the new SameSite attribute for cookies can be helpful in preventing CSRF. Most sites should be able to add SameSite=lax to their session cookies without problems. More details here http://www.sjoerdlangkemper.nl/2016/04/14/preventing-csrf-with-samesite-cookie-attribute/

I realize this is yet another patch on a far from perfect security protocol. But for those who are sticking (or stuck) with cookies for session tokens, SameSite is something they should definitely consider.

James Kettle said...


Good point, I meant to link to SameSite when I linked to Origin. I've fixed the post.

David Wippel said...

Only problem i have with WebStorage are static assets like images. With cookies i'm able to secure them too because the cookie is sent along the request but there is no way to add information from WebStorage to the request without JavaScript...

Anonymous said...

If I understand correctly you claim HttpOnly to be useless on the basis that (a) attacker will surely use more sophisticated methods, (b) an article who's reasoning against them can be summed up as "I think they are useless therefore they are" with no backing other then the same argument of attackers will use more sophisticated methods.

Attackers will use the dumbest most stupid way possible to get in. If your site can be exploited by simply increment an ID then they'll use that. This reasoning that we should ignore one potentially exploitable vulnerability just because "there are more fancier ways" is absurd.

James Kettle said...


I'm not advocating ignoring a potentially exploitable vulnerability - httponly does not prevent a vulnerability. All httponly does is prevent the oldest of many many exploit mechanisms for XSS. I agree that attackers will take the simplest effective exploit route available - my argument is that cookie theft is fiddly and unreliable, and dropping a BeEF hook or using XSS for CSRF is really quite easy. All the flag will do is slightly slow down the most incompetent attackers. There are plenty of other routes to achieve the same level of security - just tie sessions to the users' IP address. or even their user agent. I haven't recommended these because they add complexity and virtually no security gain, just like the HttpOnly flag.

James Kettle said...

I would argue that If someone is thwarted by the HttpOnly flag, they'd be equally thwarted by tokens being placed anywhere other than cookies. Either option will break their copy+paste exploit.

Anonymous said...

So cookies are bad because although they prevent XSS from stealing your sessions directly, they allow fancier attacks such as CSRF. However, if you move the session token to local/session storage, aren't you vulnerable to XSS again? This seems like a step backwards to me. Wouldn't an attacker just read your session token out of storage, transmit it and use it? Or is this assuming that all XSS is mitigated at this point and therefore CSRF is the only concern?

James Kettle said...


If you have XSS you are equally stuffed regardless of whether you are using web storage or cookies.

Nick Perez said...

Set a strict content security policy to mitigate XSS