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

[gear] Make csrf cookie samesite=strict #14180

Merged
merged 1 commit into from
Jan 24, 2024

Conversation

daniel-goldstein
Copy link
Contributor

@daniel-goldstein daniel-goldstein commented Jan 19, 2024

Currently, the _csrf cookie is made available to all subdomains of .hail.is. This means that if I first visit batch.hail.is I get a _csrf cookie set for .hail.is. That cookie is then reused if I visit ci.hail.is. Even more awkward, the same value of the cookie will get reused if I then visit batch.azure.hail.is. This isn't that big of a deal, these can all be considered part of the same application that the hail team delivers and secures, but it is very little work to set stricter bounds on where this cookie is sent. By removing the domain attribute and using samesite='strict', the cookie's domain will be set by the browser to the domain of the request whose response included the Set-Cookie header, e.g. batch.hail.is or internal.hail.is. Strict mode then ensures that the cookie will only be sent to that exact domain, meaning that each application is guaranteed to receive the _csrf token that it itself delivered, and a _csrf token from CI cannot be used to take actions against Batch.

This should not have an adverse impact on existing users' browser sessions. In render_template we preserve the value of an existing _csrf cookie so this change should do the following:

  • Logged in user visits a page with an existing widely scoped (.hail.is) _csrf cookie
  • The server returns a Set-Cookie header with a new _csrf cookie for strictly the batch.hail.is domain but with the same token value as the original _csrf cookie
  • The user now has two cookies and the browser could send either one on a given request, but it does not matter because they have the same value
  • If the user logs out and back in, their old widely scoped cookie will be cleared and they only get the strict cookie from now on.

@@ -98,6 +96,5 @@ async def render_template(
context['csrf_token'] = csrf_token

response = aiohttp_jinja2.render_template(file, request, context)
domain = cookie_domain or deploy_config._domain
response.set_cookie('_csrf', csrf_token, domain=domain, secure=True, httponly=True)
response.set_cookie('_csrf', csrf_token, secure=True, httponly=True, samesite='strict')
Copy link
Contributor

@danking danking Jan 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I feel like I'm now a bit confused about our previous conversation.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#strict

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value

It sounds like Strict is necessary for CSRF to work: otherwise I could put this on an evil website (excuse my totally invented HTML, I didn't bother to look up the right syntax and attribute names) and trick people into cancelling their batches, right?

<form method="POST" url="https://batch.hail.is/batches/123/cancel">
<button>
</form>

In particular, do we have any CSRF protection at all right now?


I agree we should remove the domain attribute:

Only the current domain can be set as the value, or a domain of a higher order, unless it is a public suffix. Setting the domain will make the cookie available to it, as well as to all its subdomains.

If omitted, this attribute defaults to the host of the current document URL, not including subdomains.

Copy link
Contributor Author

@daniel-goldstein daniel-goldstein Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server compares the cookie value to a value in the request (hidden value in the form), which means that in order to create a malicious form the evil site would need to know the value of the cookie which it can't because it is not the same origin (assuming they have not achieved the ability to set a cookie on our domain in which case signing our cookies would help)

Copy link
Contributor

@danking danking left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

@danking danking merged commit 0411c89 into hail-is:main Jan 24, 2024
7 checks passed
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

Successfully merging this pull request may close these issues.

2 participants