Hi Josh, On 08/31/2015 09:38 AM, Joshua Kehn wrote: > I understand why the Referrer check for secure requests is in place. > What is currently preventing cross-domain API requests is that the check > is not configurable. I'm talking specifically about requests when > |request.is_secure()| returns |True| and an unsafe but specifically > cross-origin request is being made.
I'm not sure what you mean by "unsafe but specifically cross-origin request" here. I think the point is that the request is in fact safe, because it's coming from an approved CORS source, but there's no way to tell the CSRF middleware that. > What currently exists is a simple referrer check. > > |good_referer = 'https://%s/' % request.get_host() if not > same_origin(referer, good_referer): reason = REASON_BAD_REFERER % > (referer, good_referer) return self._reject(request, reason) | [snip detailed example] > This check is not configurable and does > not allow any hooks to bypass or alter behavior short of turning CSRF > protection off entirely. This check is not present on non-secure > requests and can cause surprise and confusion as to this new behavior > when secure requests are enabled. > > > What are some possible solutions? [snip unfeasible solutions] > What are you doing now to solve this issue? > > Added a small piece of middleware the changes the |Referer| header to a > "|good_referer|". I've had this same problem in a CORS-accessible API scenario, and I've used the same solution. Ideally the middleware should verify that the request is a valid CORS request, from an approved host, before patching the referer. Note that the most popular CORS-headers package for Django that I'm aware of (https://github.com/ottoyiu/django-cors-headers) even includes a middleware to patch the referer to get around this problem: https://github.com/ottoyiu/django-cors-headers/blob/master/corsheaders/middleware.py#L26 > Suggested Solution > > Allow specific referrer hosts to be accepted via the settings. The > change could be as simple as: > > |good_referers = [ "https://%s/" % host for host in > settings.ALLOWED_HOSTS ] if not any([same_origin(referer, good_referer) > for good_referer in good_referers]): ... | I don't think just piggybacking on `ALLOWED_HOSTS` like this is sufficient (though it would be a small improvement on the current situation). `ALLOWED_HOSTS` is meant to be a list of host names that are aliases for the _current_ server. It should not also include remote servers that are authorized for CORS requests to this server. So in your example, `dashboard.project.com` should _not_ be included in `ALLOWED_HOSTS` on `api.project.com`, so this fix wouldn't help. > Alternatively introduce a new setting that bypasses this secure referer > check. I don't think there should be a setting to disable referer checking altogether, but I do think there should be a way to make CORS and the referer check work together without having to monkey-patch the request referer. The simplest approach would be a setting which is a list of valid CSRF referer hosts. The problem with this is that it doesn't imply any validation of the request CORS headers, but maybe that's OK. If you're declaring "I trust this particular remote host not to CSRF my users," that's probably sufficient. Alternatives might include just adding CORS support to Django directly, or providing a more generic hook for third-party CORS packages to take over the referer check themselves. Carl -- 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 [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-developers. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/55E4824B.4090802%40oddbird.net. For more options, visit https://groups.google.com/d/optout.
signature.asc
Description: OpenPGP digital signature
