I want to reduce load times on my websites by moving all cookies into local storage since they seem to have the same functionality. Are there any pros/cons (especially performance-wise) in using local storage to replace cookie functionality except for the obvious compatibility issues?
Cookies and local storage serve different purposes. Cookies are primarily for reading server-side, local storage can only be read by the client-side. So the question is, in your app, who needs this data — the client or the server?
If it's your client (your JavaScript), then by all means switch. You're wasting bandwidth by sending all the data in each HTTP header.
If it's your server, local storage isn't so useful because you'd have to forward the data along somehow (with Ajax or hidden form fields or something). This might be okay if the server only needs a small subset of the total data for each request.
You'll want to leave your session cookie as a cookie either way though.
As per the technical difference, and also my understanding:
Apart from being an old way of saving data, Cookies give you a limit of 4096 bytes (4095, actually) — it's per cookie. Local Storage is as big as 10MB per domain — this Stack Overflow question also mentions it.
localStorage is an implementation of the Storage Interface. It stores data with no expiration date, and gets cleared only through JavaScript, or clearing the Browser Cache / Locally Stored Data — unlike cookie expiry.
In the context of JWTs, Stormpath have written a fairly helpful article outlining possible ways to store them, and the (dis-)advantages pertaining to each method.
It also has a short overview of XSS and CSRF attacks, and how you can combat them.
I've attached some short snippets of the article below, in case their article is taken offline/their site goes down.
Local Storage
Problems:
Web Storage (localStorage/sessionStorage) is accessible through JavaScript on the same domain. This means that any JavaScript running on your site will have access to web storage, and because of this can be vulnerable to cross-site scripting (XSS) attacks. XSS in a nutshell is a type of vulnerability where an attacker can inject JavaScript that will run on your page. Basic XSS attacks attempt to inject JavaScript through form inputs, where the attacker puts alert('You are Hacked'); into a form to see if it is run by the browser and can be viewed by other users.
Prevention:
To prevent XSS, the common response is to escape and encode all untrusted data. But this is far from the full story. In 2015, modern web apps use JavaScript hosted on CDNs or outside infrastructure. Modern web apps include 3rd party JavaScript libraries for A/B testing, funnel/market analysis, and ads. We use package managers like Bower to import other peoples’ code into our apps.
What if only one of the scripts you use is compromised? Malicious
JavaScript can be embedded on the page, and Web Storage is
compromised. These types of XSS attacks can get everyone’s Web Storage
that visits your site, without their knowledge. This is probably why a
bunch of organizations advise not to store anything of value or trust
any information in web storage. This includes session identifiers and
tokens.
As a storage mechanism, Web Storage does not enforce any secure
standards during transfer. Whoever reads Web Storage and uses it must
do their due diligence to ensure they always send the JWT over HTTPS
and never HTTP.
Cookies
Problems:
Cookies, when used with the HttpOnly cookie flag, are not accessible through JavaScript, and are immune to XSS. You can also set the Secure cookie flag to guarantee the cookie is only sent over HTTPS. This is one of the main reasons that cookies have been leveraged in the past to store tokens or session data. Modern developers are hesitant to use cookies because they traditionally required state to be stored on the server, thus breaking RESTful best practices. Cookies as a storage mechanism do not require state to be stored on the server if you are storing a JWT in the cookie. This is because the JWT encapsulates everything the server needs to serve the request.
However, cookies are vulnerable to a different type of attack:
cross-site request forgery (CSRF). A CSRF attack is a type of attack
that occurs when a malicious web site, email, or blog causes a user’s
web browser to perform an unwanted action on a trusted site on which
the user is currently authenticated. This is an exploit of how the
browser handles cookies. A cookie can only be sent to the domains in
which it is allowed. By default, this is the domain that originally
set the cookie. The cookie will be sent for a request regardless of
whether you are on galaxies.com or hahagonnahackyou.com.
Prevention:
Modern browsers support the SameSite flag, in addition to HttpOnly and Secure. The purpose of this flag is to prevent the cookie from being transmitted in cross-site requests, preventing many kinds of CSRF attack.
For browsers that do not support SameSite, CSRF can be prevented by using synchronized token patterns. This
sounds complicated, but all modern web frameworks have support for
this.
For example, AngularJS has a solution to validate that the cookie is
accessible by only your domain. Straight from AngularJS docs:
When performing XHR requests, the $http service reads a token from a
cookie (by default, XSRF-TOKEN) and sets it as an HTTP header
(X-XSRF-TOKEN). Since only JavaScript that runs on your domain can
read the cookie, your server can be assured that the XHR came from
JavaScript running on your domain. You can make this CSRF protection
stateless by including a xsrfToken JWT claim:
{
"iss": "http://galaxies.com",
"exp": 1300819380,
"scopes": ["explorer", "solar-harvester", "seller"],
"sub": "tom#andromeda.com",
"xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e"
}
Leveraging your web app framework’s CSRF protection makes cookies rock
solid for storing a JWT. CSRF can also be partially prevented by
checking the HTTP Referer and Origin header from your API. CSRF
attacks will have Referer and Origin headers that are unrelated to
your application.
The full article can be found here:
https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/
They also have a helpful article on how to best design and implement JWTs, with regards to the structure of the token itself:
https://stormpath.com/blog/jwt-the-right-way/
With localStorage, web applications can store data locally within the user's browser. Before HTML5, application data had to be stored in cookies, included in every server request. Large amounts of data can be stored locally, without affecting website performance. Although localStorage is more modern, there are some pros and cons to both techniques.
Cookies
Pros
Legacy support (it's been around forever)
Persistent data
Expiration dates
Cookies can be marked as HTTPOnly which might limit XSS atacks to user browser during his sesion (does not guarantee full immunity to XSS atacks).
Cons
Each domain stores all its cookies in a single string, which can make
parsing data difficult
Data is unencrypted, which becomes an issue because... ... though
small in size, cookies are sent with every HTTP request Limited size
(4KB)
Local storage
Pros
Support by most modern browsers
Persistent data that is stored directly in the browser
Same-origin rules apply to local storage data
Is not sent with every HTTP request
~5MB storage per domain (that's 5120KB)
Cons
Not supported by anything before: IE 8, Firefox 3.5, Safari 4, Chrome 4, Opera 10.5, iOS 2.0, Android 2.0
If the server needs stored client information you purposely have
to send it.
localStorage usage is almost identical with the session one. They have pretty much exact methods, so switching from session to localStorage is really child's play. However, if stored data is really crucial for your application, you will probably use cookies as a backup in case localStorage is not available. If you want to check browser support for localStorage, all you have to do is run this simple script:
/*
* function body that test if storage is available
* returns true if localStorage is available and false if it's not
*/
function lsTest(){
var test = 'test';
try {
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
/*
* execute Test and run our custom script
*/
if(lsTest()) {
// window.sessionStorage.setItem(name, 1); // session and storage methods are very similar
window.localStorage.setItem(name, 1);
console.log('localStorage where used'); // log
} else {
document.cookie="name=1; expires=Mon, 28 Mar 2016 12:00:00 UTC";
console.log('Cookie where used'); // log
}
"localStorage values on Secure (SSL) pages are isolated"
as someone noticed keep in mind that localStorage will not be
available if you switch from 'http' to 'https' secured protocol, where
the cookie will still be accesible. This is kind of important to
be aware of if you work with secure protocols.
Cookies:
Introduced prior to HTML5.
Has expiration date.
Cleared by JS or by Clear Browsing Data of browser or after expiration date.
Will sent to the server per each request.
The capacity is 4KB.
Only strings are able to store in cookies.
There are two types of cookies: persistent and session.
Local Storage:
Introduced with HTML5.
Does not have expiration date.
Cleared by JS or by Clear Browsing Data of the browser.
You can select when the data must be sent to the server.
The capacity is 5MB.
Data is stored indefinitely, and must be a string.
Only have one type.
Key Differences:
Capacity:
Local Storage: 10MB
Cookies: 4kb
Browser Support:
Local Storage: HTML5
Cookies: HTML4, HTML5
Storage Location:
Local Storage: Browser Only
Cookies: Browser & Server
Send With Request:
Local Storage: Yes
Cookies: No
Accessed From:
Local Storage: Any Window
Cookies: Any Window.
Expiry Date:
Local Storage: Never Expire, until done by javascript.
Cookies: Yes, Have expiry date.
Note: Use that, what suits you.
It is also worth mentioning that localStorage cannot be used when users browse in "private" mode in some versions of mobile Safari.
Quoted from WayBack Archive of MDN topic on Window.localStorage back in 2018:
Note: Starting with iOS 5.1, Safari Mobile stores localStorage data in the cache folder, which is subject to occasional clean up, at the behest of the OS, typically if space is short. Safari Mobile's Private Browsing mode also prevents writing to localStorage entirely.
Cookie:
is accessible by JavaScript so Cookie's data can be stolen by XSS
attack(Cross Site Scripting attack) but setting HttpOnly flag
to Cookie prevents the access by JavaScript so Cookie's data is
protected from XSS attack.
is vulnerable to CSRF(Cross Site Request Forgery) but setting
SameSite flag with Lax to Cookie mitigates CSRF and setting SameSite flag with Strict to Cookie prevents
CSRF.
must have expiry date so when expiry date passes, Cookie is
deleted automatically so even if you forgot to delete Cookie,
Cookie is deleted automatically because of expiry date.
is about 4KB as a common size (depending on browsers).
Local Storage:
is accessible by JavaScript so Local Storage's data can be stolen by XSS
attack(Cross Site Scripting attack) then, as logn as I researched,
there are no easy preventions for Local Storage from XSS
attack.
is not vulnerable to CSRF(Cross Site Request Forgery).
doesn't have expiry date so if you forgot to delete Local Storage
data, Local Storage data can stay forever.
is about 5MB as a common size (depending on browsers).
I recommend using Cookie for sensitive data and Local Storage for non-sensitive data.
Well, local storage speed greatly depends on the browser the client is using, as well as the operating system. Chrome or Safari on a mac could be much faster than Firefox on a PC, especially with newer APIs. As always though, testing is your friend (I could not find any benchmarks).
I really don't see a huge difference in cookie vs local storage. Also, you should be more worried about compatibility issues: not all browsers have even begun to support the new HTML5 APIs, so cookies would be your best bet for speed and compatibility.
Local storage can store up to 5mb offline data, whereas session can also store up to 5 mb data. But cookies can store only 4kb data in text format.
LOCAl and Session storage data in JSON format, thus easy to parse. But cookies data is in string format.
Related
Background: I have two apps frontend and backend. Backend is django with django rest framework. For auth I use token. Client gets the token when it logs in via post. Client sets this token to header and keeps token in localStorage. I save the token to localStorage to prevent second request after reopening the site. But I have written a lot of articles where were wrote that localsStorage is vulnerable and it is susceptible to xss attacks. And now I thing about cookies. But I don't want to rewrite my backend logic. And I'm thinking about writing the token to a cookie via js.
My question: Should I write token to the cookies? Or should I rewrite my backend application and use sessions? Or mb don't rewrite it?
Both cookies and local storage are similarly susceptible to being tampered with on the client-side: the client can see and modify both, and so can any (possibly malicious) extensions they have. But if the connection to your site is over HTTPS and their browser/OS/hardware doesn't have something malicious snooping on things, then there shouldn't be an issue with either cookies or local storage.
The main difference between them is that cookies get sent to the server with every network request, whereas local storage stays on the user's hard drive and doesn't get sent to the server.
Cookies are arguably a little bit more vulnerable than local storage because if a cookie gets sent over an unencrypted connection, it can be intercepted - but local storage stays on the client's machine, so there's less chance of it being intercepted by something malicious. But if the connection is encrypted, which it should be, using cookies will be fine.
If your script requires the token to be sent with requests to the server, you should probably use cookies so you can examine them on your back-end. (If you use local storage instead, you'll have to manually send the token with every request, which is still possible, but a bit inelegant given that cookies can do the same thing without requiring manual intervention on your part.)
If your script doesn't require the token to be sent with every request, then feel free to use local storage instead if you want. If the server never needs to see the token after it's been generated, then don't use cookies, since it'll be unnecessary overhead for no reason.
The same general logic above applies to any data on the client-side. If the server often or sometimes needs to see it, cookies are a good choice, if the data isn't too large. If the server never needs to see it, cookies are the wrong choice.
I am using React SPA, Express, Express-session, Passport, and JWT.
I'm confused about some of the different client-side storage options to store tokens: Cookies, Session, and JWT / Passport.
Do tokens have to be stored in cookies, even if I can store them in req.sessionID?
Many websites use cookies to store shopping cart tokens. So far I have stored shopping cart data based on the session ID without adding any cookies.
So when users visit my website, I will match it with their
req.sessionID and then retrieve the data in the database like shopping carts and user session.
Do I need to store cookies? I can access it via req.sessionID to get the data needed.
And the second
I have made authentication using a passport-google-oauth20.After I successfully login, the data is saved into the session. and to send it to the client I have to send it via the URL query ?token='sdsaxas'.
in this case I get a lot of difference of opinion. someone saved it
into local storage and someone saved it into cookies by converting it to a token using JWT.
jwt.sign(
payload,
keys.jwt.secretOrPrivateKey,
{
expiresIn:keys.jwt.expiresIn // < i dont know what is this expired for cookies or localstorage ?
}, (err, token) => {
res.redirect(keys.origin.url + "?token=" + token);
});
Can I indeed store everything related to the session by using sessionID (without cookies or localstorage)?
Only by doing fetch once or every page refresh and retrieving the data and then saved into redux because I use React SPA.
This answer is based on the stateless approach and therefore it doesn't talk about the traditional session management
You have asked two altogether different questions:
Shopping cart - which is more related to business functionality
OAuth 2 & JWT - which is related to security and authentication
As a user of an ecommerce website, I'd expect that any item I add to my shopping cart from my mobile device while commuting to my workplace, should be available in the cart when I login to the website from my PC after reaching home. Therefore, the cart data should be saved in the back-end DB and linked to my user account.
When it comes to authentication using OAuth 2.0, the JWT access token and / or refresh token need to be stored somewhere in the client device, so that once the user authenticates himself by providing login credentials, he doesn't need to provide his credentials again to navigate through the website. In this context, the browser local storage, session storage and cookies are all valid options. However, note that here the cookie is not linked to any session on the server side. In other words, the cookie doesn't store any session id. The cookie is merely used as a storage for access token which is passed to the server with every http request and the server then validates the token using the digital signature to ensure that it is not tampered and it is not expired.
Although all three storage options for access and / or refresh tokens are popular, cookie seems to be the most secured option when used in the correct way.
To understand this better, I recommend you read this and this along with the OAuth 2.0 specification.
Update On 16-Feb-2019
I said earlier that cookie seems to be the most secured options. I'd like to further clarify the point here.
The reason I think browser localStorage and sessionStorage do not provide enough security for storing auth tokens are as follows:
If XSS occurs, the malicious script can easily read the tokens from there and send them to a remote server. There on-wards the remote server or attacker would have no problem in impersonating the victim user.
localStorage and sessionStorage are not shared across sub-domains. So, if we have two SPA running on different sub-domains, we won't get the SSO functionality because the token stored by one app won't be available to the other app within the organization. There are some solutions using iframe, but those look more like workarounds rather than a good solution. And when the response header X-Frame-Options is used to avoid clickjacking attacks with iframe, any solution with iframe is out of question.
These risks can, however, be mitigated by using a fingerprint (as mentioned in OWASP JWT Cheat Sheet) which again in turn requires a cookie.
The idea of fingerprint is, generate a cryptographically strong random string of bytes. The Base64 string of the raw string will then be stored in a HttpOnly, Secure, SameSite cookie with name prefix __Secure-. Proper values for Domain and Path attributes should be used as per business requirement. A SHA256 hash of the string will also be passed in a claim of JWT. Thus even if an XSS attack sends the JWT access token to an attacker controlled remote server, it cannot send the original string in cookie and as a result the server can reject the request based on the absence of the cookie. The cookie being HttpOnly cannot be read by XSS scripts.
Therefore, even when we use localStorage and sessionStorage, we have to use a cookie to make it secured. On top of that, we add the sub-domain restriction as mentioned above.
Now, the only concern about using a cookie to store JWT is, CSRF attack. Since we use SameSite cookie, CSRF is mitigated because cross-site requests (AJAX or just through hyperlinks) are not possible. If the site is used in any old browser or some other not so popular browsers that do not support SameSite cookie, we can still mitigate CSRF by additionally using a CSRF cookie with a cryptographically strong random value such that every AJAX request reads the cookie value and add the cookie value in a custom HTTP header (except GET and HEAD requests which are not supposed to do any state modifications). Since CSRF cannot read anything due to same origin policy and it is based on exploiting the unsafe HTTP methods like POST, PUT and DELETE, this CSRF cookie will mitigate the CSRF risk. This approach of using CSRF cookie is used by all modern SPA frameworks. The Angular approach is mentioned here.
Also, since the cookie is httpOnly and Secured, XSS script cannot read it. Thus XSS is also mitigated.
It may be also worth mentioning that XSS and script injection can be further mitigated by using appropriate content-security-policy response header.
Other CSRF mitigation approaches
State Variable (Auth0 uses it) - The client will generate and pass with every request a cryptographically strong random nonce which the server will echo back along with its response allowing the client to validate the nonce. It's explained in Auth0 doc.
Always check the referer header and accept requests only when referer is a trusted domain. If referer header is absent or a non-whitelisted domain, simply reject the request. When using SSL/TLS referrer is usually present. Landing pages (that is mostly informational and not containing login form or any secured content) may be little relaxed and allow requests with missing referer header.
TRACE HTTP method should be blocked in the server as this can be used to read the httpOnly cookie.
Also, set the header Strict-Transport-Security: max-age=; includeSubDomains to allow only secured connections to prevent any man-in-the-middle overwrite the CSRF cookies from a sub-domain.
LocalStorage/SessionStorage is vulnerable to XXS attacks. Access Token can be read by JavaScript.
Cookies, with httpOnly, secure and SameSite=strict flags, are more secure. Access Token and its payload can not be accessed by JavaScript.
BUT, if there is an XSS vulnerability, the attacker would be able to send requests as the authenticated user anyway because the malicious script does not need to read the cookie value, cookies could be sent by the browser automatically.
This statement is true but the risks are different.
With cookies, the access token is still hidden, attackers could only carry out “onsite” attacks. The malicious scripts injected into the web app could be limited, or it might not be very easy to change/inject more scripts. Users or web apps might need to be targeted first by attackers. These conditions limit the scale of the attack.
With localStorage, attackers can read the access token and carry out attacks remotely. They can even share the token with other attackers and cause more serious damage. If attackers manage to inject malicious scripts in CDNs, let’s say google fonts API, attackers would be able to siphon access token and URLs from all websites that use the comprised CDN, and easily find new targets. Websites that use localStorage are more easily to become targets.
For the sake of arguments
A pen-testing might flag your use of localStorage for sensitive data as a risk.
If it was ok for JavaScript to read access token from localStorage from an XSS attack, why do you think the httpOnly flag is still recommended by everyone.
Recommendation from OWASP
Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
https://medium.com/#coolgk/localstorage-vs-cookie-for-jwt-access-token-war-in-short-943fb23239ca
HTTP is a stateless protocol. Read that answer for more detail, but essentially that means that HTTP servers, such as your web server, do not store any information about clients beyond the lifetime of one request. This is a problem for web apps because it means you can't remember which user is logged in.
Cookies were invented as the solution to this. Cookies are textual data that the client and server send back and forth on every request. They allow you to effectively maintain application state data, by having the client and server agree on what they remember each time they communicate.
This means, fundamentally, you cannot have a session without a cookie. There must be a cookie that stores at least the session ID, so that you can find out which user is currently logged into your app by looking up the session. This is what express-session does: the documentation for the main session method explicitly notes that the session ID is stored in a cookie.
so my question is do I need to store cookies?because I can access it via req.sessionID to get the data needed.
You don't need to store cookies. express-session will do this for you. Your application as a whole does need to store a cookie; without it, you wouldn't have a req.sessionID to look up.
According to my experience, just store token in localStorage.
localStorage:
it can store information up tp 5MB. You do not need to ask user's permission to store token in localStorage.
The only concern is that whether the target device support localStorage api.
Check here: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
It is widely supported. But according to my experience, if you have an ios app, and there is a html page in this app which ask the user to store token (also called webview), the localStorage api cannot be recognized and throw an error.
The solution is simply i just put token in url and transfer it every time. In webview, url is not visible.
Cookie:
It is a very old style to store info locally. Storage in cookie is relatively small and you need to ask user's permission in order to store token in cookie.
Cookies are sent with every request, so they can worsen performance (especially for mobile data connections). Modern APIs for client storage are the Web storage API (localStorage and sessionStorage) and IndexedDB.
(https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)
Do not store token in sessionStorage or redux.
Data stored in sessionStorage will be lost if the tab is closed. If a user accidentally closed a tab, the token is lost and the server will not be able to identify the current user.
Token stored in redux is not different to be stored in other js files. redux store is just another js file. information stored in redux get lost for every page refresh.
In conclusion,
most of the time, token is stored in localStorage if using a modern style. In certain scenarios, you can store token in cookie and may be put in url sometimes. But never store in session.
Hope it helps.
I'm familiar with Web Storage APIs and cookies but I can't figure what is the most secure way to store an authentication token. I'm wondering if this might break any third-party libraries.
I'd like to have an exhaustive list of available methods to do so, with the pros and cons of each and the best way above all, if any.
Where to Store Your JWTs
With token-based authentication, you are given the choice of where to store the JWT. We strongly recommend that you store your tokens in local storage/session storage or a cookie.
Web Storage (local storage/session storage)
Commonly, the JWT is placed in the browsers local storage and this works well for most use cases.
When logging in a user with a username and password, the response body contains the access_token JWT. Then you need to handle this response in the client side code. This token can then be stored in localStorage or sessionStorage.
Click here for an example using sessionStorage
Both localStorage and sessionStorage both extend Storage. The only difference between them is the persistance of the data:
localStorage - data persists until explicitly deleted. Changes made are saved and available for all current and future visits to the site.
sessionStorage - Changes made are saved and available for the current page, as well as future visits to the site on the same window. Once the window is closed, the storage is deleted.
Web Storage Disadvantages
Unlike cookies, local storage is sandboxed to a specific domain and its data cannot be accessed by any other domain including sub-domains.
Web Storage is accessible through JavaScript on the same domain so any JavaScript running on your site will have access to web storage, and because of this can be vulnerable to cross-site scripting (XSS) attacks.
The developer must ensure that the JWT is always sent over HTTPS and never HTTP.
Using Cookies
You can also use cookies to store the JWT. The exact way to set a cookie depends on the client side language you are using.
There are different options to control the lifetime of a cookie:
Cookies can be destroyed after the browser is closed (session cookies).
Implement a server side check (typically done for you by the web framework in use), and you could implement expiration or sliding window expiration.
Cookies can be persistent (not destroyed after the browser is closed) with an expiration.
Cookies can be read by both the JavaScript and the server side code or only server side if the httpOnly flag is set.
Cookie Disadvantages
The max size of a cookie is only 4kb so that may be problematic if you have many claims attached to the token.
Cookies can be vulnerable cross-site request forgery (CSRF or XSRF) attacks. This type of attack occurs when a malicious web site causes a user’s web browser to perform an unwanted action on a trusted site where the user is currently authenticated. This is an exploit of how the browser handles cookies. Using a web app framework’s CSRF protection makes cookies a secure option for storing a JWT. CSRF can also be partially prevented by checking the HTTP Referer and Origin header.
Can be difficult to implement if the application requires cross-domain access. Cookies have additional properties (Domain/Path) that can be modified to allow you to specify where the cookie is allowed to be sent.
Original article: https://auth0.com/docs/security/store-tokens#how-to-implement
JWTs should never be stored in your localStorage
In fact, they shouldn't even be stored in your cookies, unless you are able to implement very strict CSRF protection
Checkout this for motivation
JWT as an id_token is like your user credentials
JWT as an access_token is like your session token
The most secure option is in-memory. Checkout this for a deep dive
I want to reduce load times on my websites by moving all cookies into local storage since they seem to have the same functionality. Are there any pros/cons (especially performance-wise) in using local storage to replace cookie functionality except for the obvious compatibility issues?
Cookies and local storage serve different purposes. Cookies are primarily for reading server-side, local storage can only be read by the client-side. So the question is, in your app, who needs this data — the client or the server?
If it's your client (your JavaScript), then by all means switch. You're wasting bandwidth by sending all the data in each HTTP header.
If it's your server, local storage isn't so useful because you'd have to forward the data along somehow (with Ajax or hidden form fields or something). This might be okay if the server only needs a small subset of the total data for each request.
You'll want to leave your session cookie as a cookie either way though.
As per the technical difference, and also my understanding:
Apart from being an old way of saving data, Cookies give you a limit of 4096 bytes (4095, actually) — it's per cookie. Local Storage is as big as 10MB per domain — this Stack Overflow question also mentions it.
localStorage is an implementation of the Storage Interface. It stores data with no expiration date, and gets cleared only through JavaScript, or clearing the Browser Cache / Locally Stored Data — unlike cookie expiry.
In the context of JWTs, Stormpath have written a fairly helpful article outlining possible ways to store them, and the (dis-)advantages pertaining to each method.
It also has a short overview of XSS and CSRF attacks, and how you can combat them.
I've attached some short snippets of the article below, in case their article is taken offline/their site goes down.
Local Storage
Problems:
Web Storage (localStorage/sessionStorage) is accessible through JavaScript on the same domain. This means that any JavaScript running on your site will have access to web storage, and because of this can be vulnerable to cross-site scripting (XSS) attacks. XSS in a nutshell is a type of vulnerability where an attacker can inject JavaScript that will run on your page. Basic XSS attacks attempt to inject JavaScript through form inputs, where the attacker puts alert('You are Hacked'); into a form to see if it is run by the browser and can be viewed by other users.
Prevention:
To prevent XSS, the common response is to escape and encode all untrusted data. But this is far from the full story. In 2015, modern web apps use JavaScript hosted on CDNs or outside infrastructure. Modern web apps include 3rd party JavaScript libraries for A/B testing, funnel/market analysis, and ads. We use package managers like Bower to import other peoples’ code into our apps.
What if only one of the scripts you use is compromised? Malicious
JavaScript can be embedded on the page, and Web Storage is
compromised. These types of XSS attacks can get everyone’s Web Storage
that visits your site, without their knowledge. This is probably why a
bunch of organizations advise not to store anything of value or trust
any information in web storage. This includes session identifiers and
tokens.
As a storage mechanism, Web Storage does not enforce any secure
standards during transfer. Whoever reads Web Storage and uses it must
do their due diligence to ensure they always send the JWT over HTTPS
and never HTTP.
Cookies
Problems:
Cookies, when used with the HttpOnly cookie flag, are not accessible through JavaScript, and are immune to XSS. You can also set the Secure cookie flag to guarantee the cookie is only sent over HTTPS. This is one of the main reasons that cookies have been leveraged in the past to store tokens or session data. Modern developers are hesitant to use cookies because they traditionally required state to be stored on the server, thus breaking RESTful best practices. Cookies as a storage mechanism do not require state to be stored on the server if you are storing a JWT in the cookie. This is because the JWT encapsulates everything the server needs to serve the request.
However, cookies are vulnerable to a different type of attack:
cross-site request forgery (CSRF). A CSRF attack is a type of attack
that occurs when a malicious web site, email, or blog causes a user’s
web browser to perform an unwanted action on a trusted site on which
the user is currently authenticated. This is an exploit of how the
browser handles cookies. A cookie can only be sent to the domains in
which it is allowed. By default, this is the domain that originally
set the cookie. The cookie will be sent for a request regardless of
whether you are on galaxies.com or hahagonnahackyou.com.
Prevention:
Modern browsers support the SameSite flag, in addition to HttpOnly and Secure. The purpose of this flag is to prevent the cookie from being transmitted in cross-site requests, preventing many kinds of CSRF attack.
For browsers that do not support SameSite, CSRF can be prevented by using synchronized token patterns. This
sounds complicated, but all modern web frameworks have support for
this.
For example, AngularJS has a solution to validate that the cookie is
accessible by only your domain. Straight from AngularJS docs:
When performing XHR requests, the $http service reads a token from a
cookie (by default, XSRF-TOKEN) and sets it as an HTTP header
(X-XSRF-TOKEN). Since only JavaScript that runs on your domain can
read the cookie, your server can be assured that the XHR came from
JavaScript running on your domain. You can make this CSRF protection
stateless by including a xsrfToken JWT claim:
{
"iss": "http://galaxies.com",
"exp": 1300819380,
"scopes": ["explorer", "solar-harvester", "seller"],
"sub": "tom#andromeda.com",
"xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e"
}
Leveraging your web app framework’s CSRF protection makes cookies rock
solid for storing a JWT. CSRF can also be partially prevented by
checking the HTTP Referer and Origin header from your API. CSRF
attacks will have Referer and Origin headers that are unrelated to
your application.
The full article can be found here:
https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/
They also have a helpful article on how to best design and implement JWTs, with regards to the structure of the token itself:
https://stormpath.com/blog/jwt-the-right-way/
With localStorage, web applications can store data locally within the user's browser. Before HTML5, application data had to be stored in cookies, included in every server request. Large amounts of data can be stored locally, without affecting website performance. Although localStorage is more modern, there are some pros and cons to both techniques.
Cookies
Pros
Legacy support (it's been around forever)
Persistent data
Expiration dates
Cookies can be marked as HTTPOnly which might limit XSS atacks to user browser during his sesion (does not guarantee full immunity to XSS atacks).
Cons
Each domain stores all its cookies in a single string, which can make
parsing data difficult
Data is unencrypted, which becomes an issue because... ... though
small in size, cookies are sent with every HTTP request Limited size
(4KB)
Local storage
Pros
Support by most modern browsers
Persistent data that is stored directly in the browser
Same-origin rules apply to local storage data
Is not sent with every HTTP request
~5MB storage per domain (that's 5120KB)
Cons
Not supported by anything before: IE 8, Firefox 3.5, Safari 4, Chrome 4, Opera 10.5, iOS 2.0, Android 2.0
If the server needs stored client information you purposely have
to send it.
localStorage usage is almost identical with the session one. They have pretty much exact methods, so switching from session to localStorage is really child's play. However, if stored data is really crucial for your application, you will probably use cookies as a backup in case localStorage is not available. If you want to check browser support for localStorage, all you have to do is run this simple script:
/*
* function body that test if storage is available
* returns true if localStorage is available and false if it's not
*/
function lsTest(){
var test = 'test';
try {
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
/*
* execute Test and run our custom script
*/
if(lsTest()) {
// window.sessionStorage.setItem(name, 1); // session and storage methods are very similar
window.localStorage.setItem(name, 1);
console.log('localStorage where used'); // log
} else {
document.cookie="name=1; expires=Mon, 28 Mar 2016 12:00:00 UTC";
console.log('Cookie where used'); // log
}
"localStorage values on Secure (SSL) pages are isolated"
as someone noticed keep in mind that localStorage will not be
available if you switch from 'http' to 'https' secured protocol, where
the cookie will still be accesible. This is kind of important to
be aware of if you work with secure protocols.
Cookies:
Introduced prior to HTML5.
Has expiration date.
Cleared by JS or by Clear Browsing Data of browser or after expiration date.
Will sent to the server per each request.
The capacity is 4KB.
Only strings are able to store in cookies.
There are two types of cookies: persistent and session.
Local Storage:
Introduced with HTML5.
Does not have expiration date.
Cleared by JS or by Clear Browsing Data of the browser.
You can select when the data must be sent to the server.
The capacity is 5MB.
Data is stored indefinitely, and must be a string.
Only have one type.
Key Differences:
Capacity:
Local Storage: 10MB
Cookies: 4kb
Browser Support:
Local Storage: HTML5
Cookies: HTML4, HTML5
Storage Location:
Local Storage: Browser Only
Cookies: Browser & Server
Send With Request:
Local Storage: Yes
Cookies: No
Accessed From:
Local Storage: Any Window
Cookies: Any Window.
Expiry Date:
Local Storage: Never Expire, until done by javascript.
Cookies: Yes, Have expiry date.
Note: Use that, what suits you.
It is also worth mentioning that localStorage cannot be used when users browse in "private" mode in some versions of mobile Safari.
Quoted from WayBack Archive of MDN topic on Window.localStorage back in 2018:
Note: Starting with iOS 5.1, Safari Mobile stores localStorage data in the cache folder, which is subject to occasional clean up, at the behest of the OS, typically if space is short. Safari Mobile's Private Browsing mode also prevents writing to localStorage entirely.
Cookie:
is accessible by JavaScript so Cookie's data can be stolen by XSS
attack(Cross Site Scripting attack) but setting HttpOnly flag
to Cookie prevents the access by JavaScript so Cookie's data is
protected from XSS attack.
is vulnerable to CSRF(Cross Site Request Forgery) but setting
SameSite flag with Lax to Cookie mitigates CSRF and setting SameSite flag with Strict to Cookie prevents
CSRF.
must have expiry date so when expiry date passes, Cookie is
deleted automatically so even if you forgot to delete Cookie,
Cookie is deleted automatically because of expiry date.
is about 4KB as a common size (depending on browsers).
Local Storage:
is accessible by JavaScript so Local Storage's data can be stolen by XSS
attack(Cross Site Scripting attack) then, as logn as I researched,
there are no easy preventions for Local Storage from XSS
attack.
is not vulnerable to CSRF(Cross Site Request Forgery).
doesn't have expiry date so if you forgot to delete Local Storage
data, Local Storage data can stay forever.
is about 5MB as a common size (depending on browsers).
I recommend using Cookie for sensitive data and Local Storage for non-sensitive data.
Well, local storage speed greatly depends on the browser the client is using, as well as the operating system. Chrome or Safari on a mac could be much faster than Firefox on a PC, especially with newer APIs. As always though, testing is your friend (I could not find any benchmarks).
I really don't see a huge difference in cookie vs local storage. Also, you should be more worried about compatibility issues: not all browsers have even begun to support the new HTML5 APIs, so cookies would be your best bet for speed and compatibility.
Local storage can store up to 5mb offline data, whereas session can also store up to 5 mb data. But cookies can store only 4kb data in text format.
LOCAl and Session storage data in JSON format, thus easy to parse. But cookies data is in string format.
On my previous websites, I used to use a cookie to display a pre-home page only on the first visit. That worked great (see for example here), but using cookies is not so trendy today, so I want to avoid it as much as possible.
Now, my new website projects almost always have pre-home launched via javascript (showing a modalbox), so I don't need to do any action on the server side. I'm considering to use HTML5 localStorage instead of cookies, with a fallback on cookies if the browser does not have localStorage. Is this a good idea? What is the impact in terms of usability, privacy protection and website performance?
Using localStorage will improve usability for users that have disabled cookies. But I know that some HTML5 features are only opt-in (like geolocalisation) in some browser. Is there any restriction like that for localStorage on any browser ? Is there any case where I will get a JS error if localStorage is available but deactivated for my site ?
Usability
The user will not know if you are using localStorage or a cookie. If a user disable cookies, localStorage will not work either.
Performance
There is no noticeable speed difference between the two methods.
sessionStorage
sessionStorage is only for that browser tab's session. If you close the tab, the session will be lost and the data will be lost too, it's similar to a session variable on any backend language.
localStorage
localStorage will be available for any tab or window in the browser, and will exist until it is deleted by the user or the program. Unlike a cookie, you cannot setup expiration. localStorage has a much larger storage limit as well.
Your Questions
You are not using this data server side, so you don't need a cookie. localStorage is never sent to the server unlike a cookie.
If the user disables the cookies, localStorage will not work either.
Fallback Example
You can use a Modernizr to verify if localStorage is available and if not, use store a cookie instead.
if (Modernizr.localstorage) {
// supports HTML5 Storage :D
} else {
// does not support HTML5 Storage :(
}
You can also forego Modernizr and use the check typeof Storage !== 'undefined'.
Comparing LS vs cookies is comparing apples to oranges.
Cookies and LS are completely different things for different purposes. LS is a tool that allows your client (javascript code) to store its data locally, without transmitting it to the server. Cookies is a tool for the client-server communication. The whole point of cookies is to be sent over with each request.
In the past cookies were often abused to emulate the local storage, just because it was the only possibility for a javascript application to write anything to the client's hard drive. But generally LS is not a replacement for cookies, so if you need something that both client and server should read and write, use cookies, not LS.
One point to add, unlike cookie normally shared cross protocol, the storages stick to same-origin policy. As a consequence sites share the same domain but hosted on different protocol do not share the stored data.
Say if your website need to work across http and https. For example, when user clicked the "purchase link" they will land on https secured checkout, then the checkout won't be able to retrieve the data previously stored on http site, even when they share the same domain.
It doesn't look easy for the server to read the localStorage. That may come in handy though, knowing your data is all client-side, making it safe from sniffing.
Cookies can't be written over, only added to and read:
alert(document.cookie);
document.cookie = "nope";
alert(document.cookie);
The one thing I didn't like about using 'localstorage' is that all your script code is visible when you 'inspect' (F12) the page. Go into SOURCES and from the left panel locate your website name and open it. All your code within the tags is totally visible. So if you've got some sensitive values on display, liked hashed passwords, special words, they all there for the world to see. I'm not sure what the world will do with this info, but it's not very secure.