1. 21
  1.  

  2. 18

    The article seems to put forward two seemingly separate arguments, that localStorage is not a good API and that localStorage is insecure. I see these as separate issues. I don’t have a particularly strong opinion about whether or not the API is good or bad, it is what it is. However I do think that calling localStorage insecure is unfair. It’s no more secure or insecure than anything else in the browser: if you’re giving 3rd parties access to your website you’re inherently trusting them.

    Things are getting completely out of hand.

    Almost every day I stumble across a new website storing sensitive user information in local storage and it bothers me to know that so many developers are opening themselves up to catastrophic security issues by doing so.

    […]

    And the thing about local storage is that it is not secure! Not at all! Everyone who uses local storage to store sensitive information such as session data, user details, credit card info (even temporarily!) and anything else you wouldn’t want publicly posted to Facebook is doing it wrong.

    [yadda yadda yadda XSS]

    So to err on the side of caution and dramatically reduce your risk for a security incident: don’t store anything sensitive in local storage.

    The argument boils down to “don’t use localStorage because it’s susceptible to XSS attacks” and I disagree wholeheartedly. XSS is basically game-over in the context of a website, so building your application under the assumption you’re vulnerable to XSS is, I think, misguided. I think it’s better to work your darnedest to prevent XSS attacks, and between Content Security Policy (CSP) and Subresource Integrity (SRI) I think developers have the tools they need (in modern browsers, granted*) to do so.

    * That said, the author talks about using SameSite=strict, which has poorer support than CSP 2, let alone CSP 1.

    Don’t tell me that JWTs are “stateless” and “fast” and you have to use local storage to store them: you’re wrong!

    JWTs are stateless and they are “fast”. Neither of those things are negated by the fact that you can use localStorage to store them.

    NOTE: For those of you who made it this far who are wondering if I didn’t read the article in its entirety because the author has notes at the bottom about CSP and SRI, I think CSP and SRI are solutions to the problems they’re describing and they seem to have tacked on hand-wavy dismissals at the end. The combination of CSP and SRI prevent XSS. The people who can’t use SRI because of 3rd-party ad networks or whatnot are inherently trusting those resources.

    The article would be better to say “if you’re blindly trusting 3rd-party code, know that they can read your localStorage values and think twice” instead of trying to make sweeping the claim that localStorage is insecure.

    1. 4

      The article seems to put forward two seemingly separate arguments, that localStorage is not a good API and that localStorage is insecure. I see these as separate issues. I don’t have a particularly strong opinion about whether or not the API is good or bad, it is what it is. However I do think that calling localStorage insecure is unfair. It’s no more secure or insecure than anything else in the browser: if you’re giving 3rd parties access to your website you’re inherently trusting them.

      You hit the nail on the head. Sorta.

      I don’t really think local storage is bad or anything, but it just seems like it has a really limited use case. What really annoys me and what prompted me to write this article is the common pattern now-a-days (adopted by 99% of web developers) where you authenticate a user, store their usre info in a JWT in local storage, and somehow believe that makes the site more secure than a cookie.

      I just wanted to emphasize how widespread XSS is, how easy it can be for your most sensitive data to be stolen (your session token), and why it’s not a good idea to trust local storage for sensitive information.

      Finally – towards the bottom of your response you mention the thing about JWTs being stateless and fast as incorrect. JWTs are stateless (and fast, sure, once they’ve been sent to the server), but:

      • Using a stateless JWT makes you store a lot of user info in a token which ends up making it larger (>4mb for almost all my sample apps). This means I’m now required to store it in local storage as cookies cap out at 4k.
      • Using JWTs requires you to build centralized revocation list patterns into your server side app (unless you don’t really care), and that requires centralization again – so you lose the stateless benefits of the JWT.
      • Using JWTs in local storage means you’ve now got to send a much larger amount of data to a web server on every request. This feels like a bad tradeoff to me. Datacenter networks will always be faster than consumer networks, and it doesn’t make sense to me to push the burden of extra data transmission to the client.
      • Using JWTs for auth means you’re directly reducing security (speed/security tradeoff). The best practice in the security world is to always perform authn/authz in realtime to get guarantees. This is impossible by design in JWTs.

      I’m just a fan of using normal sessions and keeping things simple. I wanted to present an argument for why I think it’s a better strategy and give people something to think about before blindly choosing to store sensitive info in local storage =)

      1. 1

        You missed “localstorage auth can only work with JavaScript, so your site probably sucks to use”.

        Having to load the page, parse the script, then send another request and put the results into the DOM is much slower than just serving the content in the first place.

        1. 1

          What really annoys me and what prompted me to write this article is the common pattern now-a-days (adopted by 99% of web developers) where you authenticate a user, store their usre info in a JWT in local storage, and somehow believe that makes the site more secure than a cookie.

          Maybe my point is this: the “security” of cookies and the “security” of localStorage are incomparable. I don’t think it’s correct to say one is more secure than the other. Everything in software development is about tradeoffs, to your point. They have different attack vectors and require different approaches to securing their usage. Cookies are susceptible to CSRF and localStorage is susceptible to XSS (both probably amongst other things).

          How about I propose this hypothetical: if XSS wasn’t a thing, would it then be fine to store “sensitive” information in localStorage? I think yes. If so, I think it’s more useful to work towards preventing XSS than assuming game over.

          I just wanted to emphasize how widespread XSS is

          That’s a good thing to do, I agree that web developers sometimes don’t realize how susceptible their applications are. That said, I again think the article would be better to say “if you’re blindly trusting 3rd-party code, you’re susceptible to XSS, they can read your localStorage values, and think twice about using localStorage” instead of trying to make sweeping the claim that localStorage is insecure.

      2. 3

        Do you have any examples of sensitive data being leaked because of local storage?

        I also have some bad news for you and its name is PWA.

        1. 2

          PWA’s don’t prevent you from using cookies for sessions.

          1. 1

            There are a lot of examples: I work in security for a living. I recently discovered a pretty well-known vendor of analytics services who had their CDN’d JS scripts (that tons of customers have embedded in their websites) sitting on a publicly accessible (with write access!) S3 bucket.

            For PWAs: I honestly have no idea how to secure those things. It’s hard =/

            1. 1

              Are there examples I can look at? That I can use to make the case myself. Any documented instances of the threat vectors mentioned in the article.

          2. 3

            Why focus so much on local storage? You shouldn’t store sensitive information anywhere in your browser.

            1. 3

              I solely focused on that because this is the trend I see: developers building web apps storing JWTs in localStorage. I could have focused on the larger picture but it was easier to pick on just this one pattern as it is so common.

              1. 1

                I’ve always stored them in cookies tbh, and from a security perspective - there is nothing wrong w/ storing JWTs in cookies or local storage. That’s literally what they’re for.

              2. 3

                It’s necessary to store auth tokens so you don’t need to type your password with every request.

                1. 1

                  Yep, but cookies seem to work better for that use case.

              3. 2

                Per @whymarrh’s comment I agree there are separate issues being discussed here. So, regarding how bad the localStorage API supposedly is, I have a few objections:

                you could serialize everything including data types into local storage, but that’s an ugly hack.

                Is it? I mean, everything that gets stored in a file or database somewhere does get serialized. I don’t see serializing the data you’re throwing into your key value store is a hack or ugly. JSON.stringify is ridiculously easy to use.

                It is synchronous. This means each local storage operation you run will be one-at-a-time. For complex applications this is a big no-no as it’ll slow down your app’s runtime.

                I guess if you’re reading/writing localStorage a lot in a tight loop or something this could be an issue. But to act as if this is a problem with localStorage, when it could only be a problem in particular applications - well this just seems overstated to me.

                Later in the article, the author states you shouldn’t use localStorage if you want your app to be “ultra high performance”. The localStorage API is sufficiently fast for very many use cases. If you are only doing a read or write here and there your user literally cannot detect it. I’ve worked in codebases where performance is important but never once found localStorage to be any kind of bottleneck.

                Additionally the fact that it’s synchronous, while not ideal for every situation, makes it very easy to use, which is advantageous in many situations.

                1. 1

                  Cookies are insecure because they are sent with every request automatically making them susceptible to CSRF attacks.

                  1. 2

                    CSRF prevention is well-known and widely implemented in pretty much every web framework/language. Submitting a random string in forms is pretty standard now. CSRF used to be a big problem in the late 90s but hasn’t been an issue since then.

                    1. 1
                      1. 1

                        Thats quite interesting. Thanks for the link.