Here are some notes about cookies that I keep forgetting..
Types of cookie
There are 3 kinds of cookies.
1. Session / Persistent Cookie
Session cookies are automatically removed when the browser is closed. Session cookies can be persisted by setting “expires” attribute.
document.cookie = "name=value; expires=Fri, 31 Dec 9999 23:59:59 GMT;";
If you don’t specify expires, the cookie will become session cookie automatically and removed when the session ends (all tabs are closed).
2. Secure Cookie
If you use the secure cookie, the browser will only transmit it to the server via https:// during the page load or ajax request.
document.cookie = "password=secret; secure";
Or you can set it from the server by setting following in the response header.
Set-Cookie: password=secret; secure;
Using a secure cookie prevents cookie theft by eavesdropping over the network (over plain http://), but it does not address the issues of XSS or CSRF.
3. HttpOnly Cookie
Set-Cookie: access_token=secretpanda; HttpOnly;
HttpOnly cookie does not mitigate the risk of CSRF, however.
This isn’t directly related to cookies, but if you are using a cookie for authentication, or using it to transmit sensitive information, here are some things to consider.
Let’s say there is a malicious site out there that secretly makes XHR requests to user’s bank website (maybe going through major bank sites to see if they happen to be authenticated) to transfer money to attacker’s account by using user’s cookies. if the malicious site is trusted in bank site’s CORS (although unlikely.. maybe it’s some ADs, plugins etc.. that gets injected into some pages?), then the bank website will think that it’s the user initiating such requests and happily execute the transfer.
Here are a couple of ways to mitigate such attacks from bank’s API point of view.
(Stateful) CSRF Token
For a server-side session enabled site, you can do the following.
- First of all, make sure there is no possibility of XSS (easier said than done.. but otherwise rest of the mitigations are pointless)
- Generate a random token (called CSRF token) that is associated with the user’s current session on the server side.
- Send this token on each page load and make the submit form submit the token back to the server.
- When a server receives this token, make sure that it matches the original token found in the session for that user.
Since the malicious pages won’t know the token, it won’t be able to make a request with a valid token. The only the authentic pages generated by bank’s server will have the token.
(Stateless) CSRF Token double submit
Or, if you want to make this mitigation state-less (does not require a session), you can use the double-submit method.
- (Again) First of all, make sure there is no possibility of XSS (otherwise it’s pointless.. but it’s practically hard to do)
- When a page is loaded, generate a random token and send it to the browser via the HttpOnly cookie and as a part of page load.
- Send the same token on each page and make it submitted back to the server as part of form parameters (thus called double-submit; token via form parameter, and token via HttpOnly cookie).
- When a server receives a request, make sure that the token from the cookie matches the token in the form parameter.
Since the malicious site can’t read the value of CSRF token, a malicious site doesn’t know what value to set for CSRF parameter on the submitted form. The benefit of this approach over state-ful CSRF token is that the server doesn’t need to make any additional query to authenticate the request.
Or use localstorage
The “gotchas” on above CSRF mitigations lays on the first step; make sure there is no possibility of XSS… You could make sure to escape all of your text output, but that’s just the beginning. If you are using any external libraries written by someone else, how confident are you that none of those libraries you depend on does not include any bug that could allow XSS attacks? Or how about some random browser extensions that user might be using? All browser extensions are basically a forced XSS.
Since there is no way to be 100% XSS free with cookies anyway, I often use localstorage to store access token (JWT) on my apps. I have more control over localstorage like when to send what information to server (cookies gets sent on every Ajax requess). With localstorage, I can store much more information for a longer period of time than cookie.
That’s all for now!