4

In the context of a web application... should sensitive tokens, such as those used for sessions, authentication and/or authorization, be stored in localStorage or an HTTPOnly cookie; or are they both acceptable approaches in different circumstances?

For the purposes of this question, assume that the token in question, whatever form it might take, could be leveraged to impersonate the user / hijack their session if it were disclosed to an adversary.

Background

My personal understanding/belief has always been that HTTPOnly cookies are the optimal security choice in these situations, due to the risks associated with cross-site scripting. OWASP's HTML5 cheat sheet recommends the same.

Pro HTTPOnly cookies:

  • A successful cross-site scripting attack cannot access the token.
  • Malicious browser extensions cannot access the token.
  • Exploiting the token is more difficult for the attacker, who has to make XMLHttpRequests through the victim's browser (when the token will be automatically attached to the request).

Pro localStorage / sessionStorage:

  • Cross-site request forgery attacks are entirely prevented.

To me, both XSS and CSRF attacks are complex to protect against and would benefit from multiple layers of security controls as a result. I.e. I see experienced development teams still produce applications with the occasional XSS and/or CSRF bug - protecting against these issues universally and at scale can be challenging.

localStorage appears to completely resolve CSRF, but leaves the token accessible to malicious JavaScript in the event of an XSS bug. HTTPonly cookies partially mitigate XSS but introduce CSRF as a new attack vector, which has to be protected via its own controls. The impact of an XSS attack is potentially higher than CSRF.

3
  • It seems you have done your homework and have a correct view of cookies and localStorage. I am not sure there is a clear-cut answer to this question.
    – Sjoerd
    Dec 11, 2018 at 8:10
  • I'd go for HTTPOnly Cookie. CSRF and XSS are both different and require separate mitigation technique for each. XSS always defeats CSRF, even protected ones. While CSRF doesn't have anything to do with XSS. It's also worth noting that we now have SameSite cookies which prevents CSRF altogether if done correctly. Dec 11, 2018 at 13:52
  • localStorage lives on the hard drive, providing a physical interception vuln that such cookies don't
    – dandavis
    Dec 12, 2018 at 17:42

2 Answers 2

2

Your description is correct. The use of cookies has the preference here in terms of security.

However, the HttpOnly flag is not the only thing that is required for optimal security. Set the SameSite flag to strict for best CSRF protection. Set the Path attribute if the scope can be narrowed to a specific path within the domain. Set the Secure flag to ensure it is broadcast over HTTPS only. Lastly, consider using the __Host- prefix.

1

Your understanding is correct, with some caveats:

Malicious browser extensions cannot access the token.

I wouldn't count on that one. A script injected into the page by an extension can't steal the cookie, but extensions have other ways to be malicious (e.g. filtering requests the way ad-blocking and tracker-blocking extensions do) and those might be able to see HttpOnly cookies, or there might be other approaches. So it'll block some malicious extensions, but maybe not all of them (might depend on the specific browser, too).

Exploiting the token is more difficult for the attacker, who has to make XMLHttpRequests through the victim's browser (when the token will be automatically attached to the request).

This might be easier than you think. Consider for example the open-source BeEF project, which is an easy-to-use framework for quickly and completely compromising a user's session via an injected script without needing to know the session secret (or anything else not visible to scripts). HttpOnly is a speed bump, but in many cases it's nothing more (that is, the attacker has no need for the session secret, they're only after the things that it gives them access to, and proxying requests through the victim's browser can get them those things just fine). Some people might even use BeEF when they could steal the session secret, just to avoid risks like the site noticing that the session's IP address has changed.

There are lots of ways to mitigate CSRF - the SameSite cookie flag among them, though it's a relatively weak one due to an over-generous interpretation of what constitutes a "site" - and in general I recommend using another approach that isn't cookie-based for CSRF protection (a simple one is requiring that requests include a custom header, which of course you don't configure CORS to allow for any untrusted origins; the header doesn't even need to be secret, just something that will force - and fail - a CORS pre-flight) even if you use SameSite cookies.

I'd say it's less "both XSS and CSRF attacks are complex to protect against" and more "preventing XSS is necessary in both cases; preventing CSRF is easy in both cases". As such, it really doesn't matter which approach (local storage or HttpOnly cookie) you take; use whichever one is easiest for you to do securely (will probably depend on the framework you're using, or even just in what your devs are familiar with).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .