Cookies

Here are some notes about cookies that I keep forgetting.

There are 3 kinds of cookies.

Session cookies are automatically removed when the browser is closed. Persistent cookies can be persited by setting “expires” attribute.

Like..

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.

If you use secure cookie, browser will only transmit it to the server via https:// during the page load or ajax request.

Like..

document.cookie = "password=secret; secure";

Or you can set it from server by setting following in the response header.

Set-Cookie: password=secret; secure;

Using secure cookie prevents cookie theft by eavesdropping over the network, but it does not address the issues of XSS or CSRF.

HttpOnly attribute makes the cookie invisible to Javascript running in browser (even though the cookie exists for the page from browser’s point of view). Even though Javascript can’t see the cookie, it still gets transmitted via the HTTP headers. This prevents XSS injected script to steal your cookie.. because only the server can sees them when it receives a request.

Set-Cookie: access_token=secretpanda; HttpOnly;

HttpOnly cookie does not mitigate the risk of CSRF.

CSRF Mitigation

This isn’t directly related to cookies, but if you are using cookie for authentication, or using to transmit sensitive information, here are some things to consider.

A bad site could hide (with or without the site owner’s intention) XHR requests to force your browser into to issuing requests on user’s bank website (if he/she happens to be authenticated) to send money to attacker’s account by transmitting user’s cookies. The bank website will think that it’s the user making such requests and happily execute them - especially if the bad site is trusted in bank site’s CORS (maybe they are under the same domain name?)

Recommended mitigation is to do following.

(Stateful) CSRF Token

For server side session enabled site, you can do 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 and make it submitted back to the server as part of form parameters.
  • When a server receives this token, make sure that it matches the original token found in the session for that user.

(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)
  • Generate a random token and send it to the browser via the cookie.
  • Send the same token on each page and make it submitted back to the server as part of form parameters (thus called double-submit)
  • When a server receives a request, make sure that the token from the cookie matches the token in the form parameter. Since the bad site can’t read the value of CSRF token (due to same-origin policy), bad site doesn’t know what value to set for CSRF parameter on the submitted form.

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 depends on does not include any bug that could allow XSS attacks?

Since there is no way to be 100% fool proof 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, and I can store much bigger amount of data and longer period of time than cookie.

Leave a Comment