When talking about browser storage and security, the top 1 concern is an XSS vulnerability. Having a solid understanding of what the browser storage options are and what security guarantees they offer can help developers make an informed decision on how to build an as-secure-as-possible browser storage solution.
This blog is a summary of my article from the Auth0 blog.
Browser Storage Options
The browser storage options are:
- Local Storage
- Session Storage
- In memory
Local Storage and Session Storage isolation is based on Same Origin Policy. Same Origin Policy controls access to data between websites. It restricts a document or script loaded from one origin to interact with a resource from another origin.
Session Storage has some additional protections. Data stored in Session Storage is cleared when a browser session ends and is not shared between two different browser tabs or iframes. Although this has some security benefits because of reducing the attack surface - reflected XSS attacks are not possible - it is still not considered a secure browser storage option as other types of XSS attacks can retrieve data stored in Session Storage.
Cookies offer protection against XSS only when the
HttpOnly flag is set. However, an XSS+CSRF attack can be used where the attacker injects code that performs a request to the backend. The browser will include the
HttpOnly cookie to the request allowing the attacker to retrieve the response data. At the same time the
HttpOnly cookie mandates that not even the legitimate frontend code can have access to the cookie value.
Web Workers as a Secure Browser Storage Option
Taking a step back from looking at our options and discussing what security protection they offer, what we are looking for is to write code that handles sensitive data in an untrusted environment. We’ve already looked at origin sandbox: Local Storage, Session Storage, cookies. Our verdict was that this is not a secure option with the exception of
A fundamental requirement for storing a secret within the memory of a Web Worker is that any code that requires the secret must exist within the Web Worker. If the Web Worker passes the secret to the rest of the browser application at any time, an attacker can override the
MessageChannel object and retrieve the secret when it's transferred.
Same as with
HttpOnly cookies, storing secrets within the memory of a Web Worker also protects the confidentiality of the secret. An attacker cannot obtain the value of the secret but they can use it indirectly by sending messages to the Web Worker to perform an operation that requires the secret, and returning back to them the result.
The advantage of a Web Worker implementation compared to an
HttpOnly cookie, no JS code can access the value of the secret. If access to the secret is needed by a part of the frontend application, the Web Worker implementation is the only one satisfying the requirement while preserving the secret confidentiality.
Browser Storage: Security Options Recap
If a secret cannot be kept in isolation, any browser storage is susceptible to XSS. The different storage options that provide some level of effective isolation are
HttpOnly cookies, simple cases of in-memory storage within private closures with local copies of externally defined functions and Web Workers.
None of the options are bullet proof from a security perspective; still, they protect the confidentiality of the secret. Finding the right solution depends on your application requirements but always consider moving away from a browser storage design.
Where to Learn More
Learn more about secure browser storage and dive into the details of the topics presented here in my article https://auth0.com/blog/secure-browser-storage-the-facts/ from the Auth0 blog or in my OWASP AppSecIL 2020 talk "Security Facts and Fallacies around Browser Storage": https://youtu.be/roG99LkSkZA
Browser Storage Security Playground
Play around with sample applications showcasing browser storage security nuances in: https://github.com/esarafianou/browser-storage. They show the differences between Local and Session Storage and demonstrate different in-memory storage implementations and their insecurities against XSS. Instructions and details can be found in my article from the Auth0 blog.