DEV Community

loading...
Cover image for localStorage vs cookies: the "tabs vs spaces" sterile debate of web development πŸ™„

localStorage vs cookies: the "tabs vs spaces" sterile debate of web development πŸ™„

oguimbal profile image Olivier Guimbal ・3 min read

EDIT: The title not being clear enough (I thought it was implicit): This article is about the "storing tokens in localStorage or in cookies for SPAs" debate. It is NOT about using cookies to store general purpose data.

I'm a tad tired of reading "dont use localStorage, it's not secure". Why ? Oh, yes "its accessible in JS". Let me tell you how this seems to be an overrated argument to me.

duty calls

If someone owns you, someone owns you.

If someone can run arbitrary JS on your website, do you really believe a peremptible JWT will necessarily be the only thing that can be exploitable ?

Personally, I'd go with something far more interesting to me: Collecting what user are typing in password boxes. Or just performing the requests that interest me directly from their browser. Those exploits are even easier to write when using cookies, given that you dont have to guess where is the token stored nor how to use it.

Cookies also have their drawbacks

  • Protecting against CSRF is not that easy, and beginners are not even aware of it.
  • Implementation of multiple authentication is harder (if you're writing a signle API that must be usable in multiple websites)
  • You cant control them (easily tell if you're logged-in, read associated data, ...)
  • CORS is harder with them.
  • etc...

XSS / Malicious JS dependencies: The easy fix.

You're worried that one of your dependencies might be accessing your localStorage maliciously ?

Well, that's not a strong valid argument, you could just prevent it to do so like that when bootstraping your application:

const storage = localStorage;
delete localStorage;
Enter fullscreen mode Exit fullscreen mode

And voilΓ  ! There is no more localStorage exposed in your window, but you still can access your tokens via the "storage" local variable (of course, you must keep it in a private scope).

These two lines of code will protect you from the most obvious and common exploit that localStorage is blamed for.

(of course you could imagine spying tokens by overriding fetch or equivalent, but that also is mitigable... its about preventing 99% of exploits, this is not strong security)

If other parts of your app need to access local storage, you could set window.localStorage to a proxy that only lets the user access non critical parts of your local storage, leaving your precious tokens out of their sight.

Which one to use then ?

I think that the web has more suffered (and is still suffering) from CSRF attacks compared to stolen JWTs, so dont tell me that https cookies are the secure way to go. Unless you're writing ultra-secure and highly-reviewed code, no, they're not. Its easier to make mistakes with cookies compared with localStorage tokens.

Just to be clear: I dont prefer one over another... I'm just saying that this debate is a bit useless, both approaches having their own sweetspots and weakspots.

I'm just sick of people explaining you otherwise with a condescending tone just because they think they've understood all there is to know by saying "its accessible by JS". Or because they've read somewhere that localStorage tokens might be considered as a potential security leak by some. Give me a break. The world is about nuance, not about dogmas.

Happy to hear what you think of this in the comments.

Discussion (20)

Collapse
jmau111 profile image
Julien Maury

I would say the client-side is probably not the right candidate for critical information.

People often say it's "insecure", but I agree with you on the fact it's rarely exploitable, and if anyone manages to do that, you have a big problem anyway.

A lot of so-called best practices follow the same pattern. The idea is to provide some guidelines and prevent any misuses.

However, and it's a big disclaimer, as developers, rather than accepting what we read or listen to at face value, we need to be critical.

Collapse
sleeplessbyte profile image
Derk-Jan Karrenbeld • Edited

Saying "don't use localStorage because its accessible by JavaScript" is indeed a very bad argument but doesn't really say anything. Don't use if for what? This article is, just like the premise, comparing apples to oranges.

I think from your article you meant that people say that localStorage shouldn't be used as a storage mechanism for authentication/authorization tokens. That means that the real debate is session in a cookie vs 'token-that-will-likely-be-stored-via-a-storage-api-such-as-localstorage'.

That said. Using localStorage is fine. Using JWTs is overrated and in most cases actually done insecurely. I don't think anyone should be condescending when mentioning this, but I think they often are because they don't understand why it's seen as problematic by those in SecOps.

Collapse
oguimbal profile image
Olivier Guimbal Author • Edited

Yup, you're right, I did not specifically mention that it was "localstorage as a mean to store auth tokens". I thought it was kind of implicit πŸ˜‘.

I agree, things are most often actually implementd insecurely. That statement also applies to cookie usage, and lets be honest, to the pretty much everything when you're dealing with security...

Collapse
sleeplessbyte profile image
Derk-Jan Karrenbeld

It might have been the implicit intention, but I do think there is a big difference between discussing JWTs stored in localstorage or localstorage as a technology.

Regardless, Sven Slootweg made two compelling posts in 2016 pointing out why using JWTs (stored in localstorage) instead of using a session cookie is a bad idea, and I think he does it without being distasteful about it.

I think that, as developer, we should be aware of these points so that when we do choose to use a JWT stored in localstorage as a session token, instead of using a cookie for session authentication, we can actively guard that we use a good implementation. So instead of saying "everything is insecure", we say "we're informed, and decided that it's Good Enoughβ„’".

People who blatantly say "don't use JWTs" or "don't use localStorage" without elaboration or without understanding the nuance of each decision are honestly not worth your (or my) time. It's indeed pointless.

I don't agree that it's the same as tabs vs spaces, but it definitely has the same level of tribalism (and with that it becomes pointless shouting instead of constructive debate).

Collapse
bpedroza profile image
Bryan

I agree with you; These arguments are kind of old and no one ever wins. For me the answer is simple. Don't ever store anything sensitive in either of these.

Collapse
darkwiiplayer profile image
DarkWiiPlayer

Don't ever store anything sensitive in either of these.

That only leaves the server, and that's the last place where you should want to store anything sensitive. Not only can you get hacked, just as the user can; said user doesn't even have any control to at least wipe the data if they want to be absolutely sure it won't be leaked.

Then there's the small but important factor that some data needs to be on the client, like session data, which can often be used to exfiltrate pretty much everything else from the server (although recently some large platforms have started to always ask for a password for certain operations, which somewhat mitigates this)

Collapse
bpedroza profile image
Bryan

What are you talking about?

The server is a MUCH safer place to store secrets. Please provide a link to any reputable article that says otherwise. If we're talking about access tokens (or any user specific secret), where do you think the token gets validated? The server HAS TO know these or there is no way to secure communication between the server and the client.

Storing secrets on the client does not inoculate your server from being hacked. Further, if the server gets hacked, the data your were trying to protect is no longer secure anyways, so the point is moot.

Typically session data need not contain sensitive information. If there is sensitive information, store it in memory. Don't persist it. For any non-sensitive data, use local or session storage to your heart's content. I'm not saying don't use these technologies, I'm saying don't persist secrets there.

Thread Thread
oguimbal profile image
Olivier Guimbal Author • Edited

Yea... I totally agree to everything you've said, I've never said anything adverse to what you're writing, so I dont understand your comment. I'm only speaking about authentication tokens storage (which must be stored clientside... and yes, obviously validated by the server on each request)

[EDIT] Sorry, I've not seen that this was not intended to me... The notification did not mention it. Leaving my comment anyway :)

Collapse
pekes317 profile image
Pekes317 • Edited

Hi, I would agree with a lot of the points made because like you said if someone is able to inject / run JS on the front-end of the app there definitely big issues already in play. Also, either localStorage or cookies can be done insecurily. I find it interesting that no one seems is talking about sessionStorage unless it assumed to be included with localStorage since they are similar in their access. But I would agree that sessionStorage has the benefit of being cleared on new tab.

Collapse
artis3n profile image
Ari Kalfus • Edited

"If someone owns you, someone owns you."

There is a LOT of room inside this statement. What do they own? Is XSS (cross-site scripting, executing arbitrary javascript) only accessible on the Contact Us form? If an attacker cannot access session credentials, then there is not much they can do with that attack.

There are significant challenges for an attacker when authentication credentials are inaccessible vs. it is incredible easy to steal user data with access to credentials. There are layers of defensive controls in place (or should be in place) on a website.

This is a good page to get started on understanding the subtleties and various other security controls in place on websites.

"Protecting against CSRF is not that easy, and beginners are not even aware of it"

See portswigger.net/web-security/csrf/...

Collapse
oguimbal profile image
Olivier Guimbal Author • Edited

Agreed, there is a lot of room in the sentence you mentioned :)
My intention was not to deliver a detailed technical article, rather to express an opinion that is not heard as much as I feel it deserves. So thanks for your link !

That said, just a precision though: when dealing with SPAs, there is no such thing as "only in contact us form"... once you've injected some JS, you're in the place until the user leaves or refreshes.

Once your injected code is running, with cookies auth, you will probably be able to perform whatever GET request against the server to steal whichever userdata you want: They'll be kindly authenticated for you by the browser.

At least, with tokens instead of cookies, you get a chance to hide your auth token in a private scope.

But anyway, my point was not to prove that one if better than another :)

Collapse
darkwiiplayer profile image
DarkWiiPlayer

Does the server need to know? Cookies. Otherwise, local storage. There's no debate to be had here.

Collapse
oguimbal profile image
Olivier Guimbal Author

That's the thing. My point is that this is a dogma that I feel is not true when you deal with smaller projects, or with junior developers. You can write broken auth mechanisms even more easily when using cookies compared to storing a token in localStorage.

See my edit (on top of the article for the "server to know" part).

Collapse
darkwiiplayer profile image
DarkWiiPlayer

You can write broken auth mechanisms using anything if you don't know what you're doing. It's the reason why we don't trust beginners to write security-related code until they have developed a good understanding of the implications.

Ultimately, if an attacker has gotten to the point of running arbitrary code in your system, be it clientside or serverside, you're screwed either way. This is an all or nothing situation. You can't be somewhat dead or, as my math teacher used to put it, there is no half pregnant (not even the weirdest one of her pet phrases).

So yes, if the server needs to know (anew with every request), a cookie is the right place to put the data. If the server generally doesn't need to know, then local storage.

Thread Thread
oguimbal profile image
Olivier Guimbal Author • Edited

Totally agree on the "all or nothing situation". But if you assume that your client is somewhat safe, then its safer to never use cookies (you're protecting yourself against XSRF), and prefer passing an 'Authorization' header in your requests filled with a token you'll keep in localStorage.

You've made me realize that this might be another confusion: I'm speaking about SPAs ... for which the only required auth is via Ajax calls (meaning you have control over headers). I'll edit more.

Thread Thread
darkwiiplayer profile image
DarkWiiPlayer

For SPAs it's a bit easier to use localstorage, but I still think cookies are the place to transmit tokens: their whole point is to transmit certain data with every request, so I don't see much of a point in re-inventing the wheel. For XSRF there's specific mechanisms to mitigate it.

What's more, with cookies, the browser keeps track of what goes to which domain, whereas if you manually insert a header into every fetch request, you might by mistake end up sending the token to the wrong domain, if an attacker finds a way to inject an off-domain URL into your application.

Thread Thread
oguimbal profile image
Olivier Guimbal Author

You can mitigate this very easily. That's what CSPs are for.

Actually, it's much more easy and reliable than mitigating XSRF, given that you just have to do it once, and it does not require any code... (you can just put the right CSP in your CDN config)

Collapse
s11637883 profile image
S • Edited

I don't want to be rude, but I'm afraid you don't know what you're talking about.
First of all, don't compare two different things. Cookies store small pieces of information that are sent to the server automatically, while the web storage API is designed to process various types of data and use them locally (in most cases).

I will tell you a story that happened to me.
I once found XSS on a website and it was so hard to hack accounts because of the httponly flag.
Without this flag, it would have taken me a minute to hack any account, and what's more, I could have hacked any account silently, but this f***g flag ruined my plans.
I had to write some scripts. One script logged the user out, the second forced the user to log in, and the last one stole the user's password.
All this was more difficult to implement, and it didn't allow me to hack any account for many reasons. To top it all off, this XSS was fixed because some users were reporting it.

This simple flag saved this site from destruction.

Collapse
oguimbal profile image
Olivier Guimbal Author • Edited

I dont want to be rude, but I'm afraid you missed my point entirely...

- and yes, you're being a bit rude begining a sentence by "I dont want to be rude" and explaining to me what a cookie is like I'm 5 ... or at least a tad condescending

Collapse
s11637883 profile image
S

Entirely !!!

Forem Open with the Forem app