I've recently been working with other new frameworks, particularly Remix. Coming from Django, which has had excellent CSRF for many years, one of my first questions was how to handle CSRF protection. And the response I got lead me to the "Lax" SameSite cookie parameter, and that I really wouldn't need more than that for the session cookie.
It appears that Django has defaulted the session cookie to `Lax` since the SESSION_COOKIE_SAMESITE parameter was added in Django 2.1. All current browsers seem to have supported it since 2019. Is it time for us to remove the CSRF Middleware from the default settings template file?
Are you implying that all CSRF attacks protected by Django's current machinery are entirely mitigated by SameSite=Lax on the _session_ cookiue?
https://security.stackexchange.com/questions/262245/are-csrf-attacks-a-thing-of-the-past
Looks like lax will do the trick, but it's not like there aren't legit cases for same-site policy to be set to something less restrictive.
LP,
Jure
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/18aaa4cf-4612-4373-bd91-90cfb3fd07b8n%40googlegroups.com.
Hello Everyone,
Looks like lax will do the trick, but it's not like there aren't legit cases for same-site policy to be set to something less restrictive.
I agree. In my experience there are legitimate cases for setting SameSite=None, especially concerning iframes.
Specifically, when developing a web app intended to be embedded as an iframe by a different top-level origin, you can't really use cookies unless their SameSite attribute is None. This is the case even if you manage the cookies entirely inside the iframe and its origin.
In such cases, you really do need Django's current CSRF protection. Personally I wouldn't mind it being off by default, since SameSite=Lax seems to be enough for most cases, but this could be a footgun for some people.
Best,
Stratos
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/86ced442-e7f9-aab8-9a03-d9c2362b60f9%40gmail.com.
In such cases, you really do need Django's current CSRF protection. Personally I wouldn't mind it being off by default, since SameSite=Lax seems to be enough for most cases, but this could be a footgun for some people.
[...] In my experience there are legitimate cases for setting SameSite=None, especially concerning iframes.
Specifically, when developing a web app intended to be embedded as an iframe by a different top-level origin, you can't really use cookies unless their SameSite attribute is None. This is the case even if you manage the cookies entirely inside the iframe and its origin.
In such cases, you really do need Django's current CSRF protection. Personally I wouldn't mind it being off by default, since SameSite=Lax seems to be enough for most cases, but this could be a footgun for some people.
In my experience, even SameSite None is not sufficient to use cookies in cross-site iframes. Safari doesn't allow those cookies to be sent unless you visit the site directly first. I've heard movements for Firefox and/or Chrome having similar behavior, but I haven't been working with iframes recently enough to know the current state of that.
You are correct about this and I've been bitten by this in the past. (Un)fortunately, I am currently involved with enterprise™ projects where Safari is a distant afterthought.
There certainly are legitimate use-cases. I like Jacob's following suggestion for a check that might help alleviate a misconfiguration concern, if they did change SameSite to none without activating CSRF protection. If it were possible to identify other places where there might be a sharp-edge misconfiguration because of the cross-domain difference of meaning between samesite and what CSRF needs, that could be good as well. And those checks would, I think, be worthwhile even without changing the default, since they are currently possible configurations.
If CSRF is turned off by default, adding such a check would be a good idea. It should definitely check for SESSION_COOKIE_SAMESITE
's value, since the session cookie is usually the one that needs protection from CSRF, but I haven't thought deeply about theotherthe cookies. This could have implications regarding HttpResponse.set_cookie
, since it can't be checked by a system check.
I think what we want to weigh is whether the footgun of *not* having CSRF by default is bigger than the significant complexity overhead of managing the CSRF projection in a new project. It's marking all views, adding tags to all form templates, and I think it can be easy to underestimate the attention it requires. If we can eliminate this overhead, especially for beginners starting out with Django and web development, that sounds like a great benefit. Lowering the barrier to entry is worth a lot.
I mostly wanted to argue against the removal of the current CSRF machinery altogether, since it is still necessary for certain use cases.
Removing it from the default template is a harder question. I completely understand the complexity point, since I've lost track of how many times I've had to explain what a CSRF error is and why you should care. Still, I'm not sure if removing it from the default template would be OK, since it would trade off security for convenience (even if only for marginal cases).
Best,
Stratos
Well, TBH, I've just completed dealing with CSRF form in my projects. I ended up exempting the particular view from CSRF because I didn't know how to get the stuff to work. The problem was that django parsed the body payload, which was JSON and thus rejected its contents (because it wasn't form payload type – POST method). As a result, DRF then had no payload to work with… I shouldn't go into too much detail as it's irrelevant to the point.
But, I've been considering I need a modernised CSRF: currently it works by generating a new token every page served. But we have switched our front-end to SPA and that doesn't make much sense any more since CSRF token itself doesn't change at all, since Django template system only ever serves one page. AFAIK, DRF doesn't ganerate new tokens in its pipelines.
Takeaway: I don't think having CSRF enabled causes any significant downsides, even with a simpler, more modern handling. It does its thing regardless and doesn't interfere if it thinks everything is ok. Otherwise, it just saved your a** 😉
LP,
Jure
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/A1CC86D7-24E6-457F-9B62-3FD4C82A775C%40gmail.com.
Well, TBH, I've just completed dealing with CSRF form in my projects. I ended up exempting the particular view from CSRF because I didn't know how to get the stuff to work. The problem was that django parsed the body payload, which was JSON and thus rejected its contents (because it wasn't form payload type – POST method). As a result, DRF then had no payload to work with… I shouldn't go into too much detail as it's irrelevant to the point.
But, I've been considering I need a modernised CSRF: currently it works by generating a new token every page served. But we have switched our front-end to SPA and that doesn't make much sense any more since CSRF token itself doesn't change at all, since Django template system only ever serves one page. AFAIK, DRF doesn't ganerate new tokens in its pipelines.
OK, I'll bite:
For the first issue, my problem revolved around this code:
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/f64582bd-63ea-483a-aebc-2acc5dac6cdbn%40googlegroups.com.
OK, I'll bite:
For the first issue, my problem revolved around this code:
@property def POST(self): # Ensure that request.POST uses our request parsing. if not _hasattr(self, '_data'): self._load_data_and_files() if is_form_media_type(self.content_type): return self._data
return QueryDict('', encoding=self._request._encoding)
IIUC, this code tries to match the token received from the headers with one that's supposed to be in the form data payload. The code is allowed to fail just fine, but in this case it has the side-effect mentioned: the form payload will have been parsed and cannot be parsed again - while at the same time rejecting the parsed data because it is not form payload type.
What I was trying to say with that paragraph was that I'd like to actually figure out a way to START doing token rotation because my observation is that it's currently NOT rotating and is therefore a lot less useful as a security measure.