Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signing Cookies #11

Closed
elithrar opened this issue Jul 24, 2014 · 8 comments
Closed

Signing Cookies #11

elithrar opened this issue Jul 24, 2014 · 8 comments

Comments

@elithrar
Copy link
Contributor

nosurf does not currently sign cookies as the standard http.Cookie implementation only defines the "basic" attributes of a cookie.

CSRF cookies should be signed (so we can identify attempts to tamper) with HMAC-SHA256, and then authenticated before checking the cookie against the submitted request. An example of a solid authentication implementation can be found here.

  • Authenticated cookies should (really) really be the default, but I'm not sure how to reconcile this without breaking the existing API. I would argue that the benefit from authenticating cookie values outweighs the downside of breaking the API. Any major change would be a compile-time error too, and is therefore easier to resolve (no weird gremlins at run-time).
  • I would also consider updating the README to stress (as it's extremely important) that package users serve their site over HTTPS (SSL/TLS), as otherwise CSRF tokens are effectively lip service given that the cookies themselves can be hijacked (and as their contents aren't authenticated, changed at whim).
  • Encrypted cookies would be an additional "nice to have" but do not really circumvent the need for SSL/TLS. The existing "encryption" references in the docs should also be changed to "masked" or "masking".
  • You would facilitate authentication/encryption by allowing a user to pass in keys in a func (h *CSRFHandler) SetAuthKeys(key []byte, keys ...[]byte) and func (h *CSRFHandler) SetEncryptionKeys(key []byte, keys ...[]byte), with the variadic param allowing a package user to pass in multiple key pairs (which facilitates cycling keys). This would be similar to how gorilla/securecookie handles key rotation, but you could probably get away with just accepting a single key.
  • Leveraging gorilla/securecookie itself may not be a bad idea. You could wrap its exported functions with your own to maintain as much of your existing API as possible, or have nosurf.New accept an options struct that then calls securecookie API before then returning a configured *CSRFHandler.
  • I'd also suggest bringing the default expiry way down to something like a week, tops. Even a day would be fine—users don't take a day to fill out a form.
@justinas
Copy link
Owner

Not sure about this one. If the attacker is a MITM, there are attack vectors that are much more dangerous (and more straightforward to execute at the same time). Simply stealing the session cookie seems much more viable for the attacker than tampering with a CSRF cookie, tricking the user into visiting the hostile website, etc.

@justinas
Copy link
Owner

Just to add to it: other CSRF implementations (like Django or Flask-SeaSurf) do not seem to use any kind of signatures on the CSRF cookies.

@elithrar
Copy link
Contributor Author

Django's cookies are signed by default. Rails is the same, since 3.0 if I
recall correctly.

The primary benefit is that you can detect any attempt to tamper: because
even a MITM over vanilla HTTP can't get the key, any modified cookie
contents would automatically fail validation. This would hold true even if
they could modify the form and the cookie contents to match.

This also benefits HTTPS connections, which are still at risk from the
above when HTTP to HTTPS redirects are in place (instead of STS headers).

On Monday, July 28, 2014, Justinas Stankevičius notifications@github.com
wrote:

Just to add to it: other CSRF implementations (like Django or
Flask-SeaSurf) do not seem to use any kind of signatures on the CSRF
cookies.


Reply to this email directly or view it on GitHub
#11 (comment).

@elithrar
Copy link
Contributor Author

I should also mention that because the cookies are not HttpOnly by default, any XSS vulnerability (which does not require a MITM!) can write to the cookies directly and avoid the same-origin policy that would normally restrict that. I assume that we don't enforce HttpOnly for convenience—so that AJAX requests can get the CSRF token—but this opens up another avenue for attack.

We can comfortably (under any reasonable circumstance) assume that no-one is going to brute-force our HMAC-SHA256 signed values, so any attempts to modify the cookie via XSS (which is going to be the most common), MITM on our users' site or even a MITM on any external scripts we use—can at least be detected and the request rejected.

@justinas
Copy link
Owner

I don't think Django signs cookies by default. As I see it, there are both set_cookie() and set_signed_cookie() functions. CsrfViewMiddleware seems to use the former.

Your point about the XSS vulnerabilities is a valid and convincing one, though. I will think about how to integrate the signing some more, mostly whether to break API and make it default (forced?).

@elithrar
Copy link
Contributor Author

Ah, good catch. Django’s default cookie store is signed (https://docs.djangoproject.com/en/dev/topics/http/sessions/#using-cookie-based-sessions) but I didn’t realise this doesn’t include their CSRF implementation. Odd!

On 29 Jul 2014, at 4:58 AM, Justinas Stankevičius notifications@github.com wrote:

I don't think Django signs cookies by default. As I see it, there are both set_cookie() and set_signed_cookie() functions. CsrfViewMiddleware seems to use the former.

Your point about the XSS vulnerabilities is a valid and convincing one, though. I will think about how to integrate the signing some more, mostly whether to break API and make it default (forced?).


Reply to this email directly or view it on GitHub.

@justinas
Copy link
Owner

This only applies to the session cookie. All other cookies are up to user to sign.

@justinas
Copy link
Owner

Well this has been sitting open for a while.

Seeing how there are now alternatives like goji-csrf which do use cookie signing and the fact that it would change the API, I think this should be considered out of scope for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants