1

I’m using an HttpOnly cookie to store authentication token client-side. To mitigate some of the risks of CSRF attacks, I’m employing the Double Submit Cookie pattern. The same token is saved client-side as a separate header with the same value, and both get sent for subsequent requests when the user is logged in.

My question: Obviously the attacker will send the HttpOnly cookie when performing a CSRF attack, but can they set a separate authorization header whose value is identical to the HttpOnly cookie, even though he can’t read the cookie’s value?

Note: I’m aware of the limitations and workarounds pertaining to DSC.

zerohedge
  • 135
  • 5

1 Answers1

1

I think you're asking the wrong question. Here is my question for you:

What's the point in creating an HTTP-only cookie if you're also storing the cookie contents outside of the secure cookie?

The whole point of making a cookie HTTP-only is that it secures the cookie contents from theft. In the event of an XSS attack, an attacker can make requests on behalf of the user, but they can't outright steal the credentials - limiting the scope and timescale of the attack (in particular, the attacker will likely lose access as soon as the user navigates to a different page).

If you also are sending your cookie contents down to the app to store in a separate way, then the HTTP-only flag on your cookie is now pointless because in the event of an XSS attack, the attacker can steal the user's access credentials in from wherever else you are storing it, since only HTTP-only cookies provide any protection against credential theft in an XSS attack.

There are many effective methods to stop CSRF attacks. As a result, if you are considering a method that also weakens another layer of security, then the answer is, quite simply, you're doing it the wrong way.

Is there a reason you aren't considering CSRF tokens or custom headers? The former are the norm and are perfectly secure, so unless you have a compelling reason not to use them, then just do it that way. If for some reason that isn't possible for you then you can fall back on custom headers, although that isn't ideal.

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
  • You are right, of course. This probably means I should be tracking *two* values in the backend. Are there any resources regarding the recommended expiration time for both credentials (CSRF token & cookies)? – zerohedge Oct 14 '19 at 15:15
  • 1
    @zerohedge The recommendation on cookies varies wildly depending on your use case and needs. For CSRF tokens though there is a more clear answer. You can technically get away with creating one on login and never refreshing it until the next login. Personally though I prefer refreshing them after each use. However, they don't need to have an expiration time. – Conor Mancone Oct 14 '19 at 15:19
  • 1
    @zerohedge https://security.stackexchange.com/questions/22903/why-refresh-csrf-token-per-form-request – Conor Mancone Oct 14 '19 at 15:21
  • Yeah. That’s what my backend (Django REST) does by default - it creates a CSRF valid for one year. I’ll see what I can do to use it since it’s disabled by default once you use REST (because of the horrible advice to use LocalStorage) – zerohedge Oct 14 '19 at 15:21
  • I’m now confused on whether what I’m doing is actually wrong after reading this: https://stackoverflow.com/questions/49298250/where-is-the-csrftoken-stored-in-django-database – zerohedge Oct 14 '19 at 15:43
  • @zerohedge A difference (unless I've misunderstood your question), is that the cookie that django uses in the double-submit-cookie CSRF auth is *NOT* the authorization cookie. I mean, you could use the auth as your double-submit-cookie, but doing so requires making your authorization cookie more susceptible to attack (by storing it in an accessible method on the client side). – Conor Mancone Oct 14 '19 at 16:13
  • In that case though I have one further question: how are you getting the token into the client request? In Django it is also writing out the cookie value into an element in the form. The cookie probably still has the HTTPOnly flag set, since it isn't being used in javascript, but since it isn't an auth cookie it doesn't matter either way. Then Django compares the value in the form against the value in the cookie. It sounds like you're doing something that is a mix between DSC and cookie-to-header: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-header_token – Conor Mancone Oct 14 '19 at 16:16
  • So, upon login, I set the HttpOnly cookie in the Django response, but I also return it in the payload - and then save it in state (`vuex` store). Then (only given the token is available in state), the Axios plugin attaches it as an `Authorization` header. This happens client-side (in a Nuxt.js plugin using an axios interceptor https://nuxtjs.org/guide/plugins/ ). – zerohedge Oct 14 '19 at 16:47
  • @zerohedge so is this your authorization cookie? It sounds like it is. To be clear, what you describe will certainly protect you from CSRF attacks. However, using your auth cookie for both authorization **and** CSRF protection is something that is likely to cause trouble in the long term. Usually, giving one thing two purposes just doesn't work out in practice. – Conor Mancone Oct 14 '19 at 17:00
  • but it DOES open me to XSS, no? – zerohedge Oct 14 '19 at 17:03
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/99881/discussion-between-conor-mancone-and-zerohedge). – Conor Mancone Oct 14 '19 at 17:25