Opened 14 months ago

Closed 14 months ago

Last modified 7 weeks ago

#34855 closed Cleanup/optimization (wontfix)

Document CSRF_TRUSTED_ORIGINS relation to SECURE_PROXY_SSL_HEADER.

Reported by: jeroenmuller Owned by: nobody
Component: Documentation Version: 4.2
Severity: Normal Keywords: CSRF
Cc: Florian Apolloner Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When the CSRF origin check fails, the documentation points in the direction of adding that origin to CSRF_ALLOWED_ORIGINS. However, as far as I understand this should only be neccessary if there are actually cross-origin requests. In practice the CSRF origin check may also fail when is proxying HTTPS traffic over HTTP without setting up SECURE_PROXY_SSL_HEADER accordingly. This problem may occur suddenly when upgrading to Django 4.0, because this version turns on the origin verification in the CSRF middleware. In that case the Django release notes point in the direction of adding the failing origin to CSRF_ALLOWED_ORIGINS: https://docs.djangoproject.com/en/4.2/releases/4.0/#csrf-trusted-origins-changes-4-0. But this is not the optimal solution, and may weaken CSRF protection if a user ends up just adding a pattern matching all subdomains or the complete ALLOWED_HOSTS lists to CSRF_ALLOWED_ORIGINS.

It might be useful to add a note or warning below https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS explaining that it should only be neccessary to configure this if you are actually making requests across subdomains, and in other cases setting up SECURE_PROXY_SSL_HEADER might be a more appropriate solution (as long as the proxy correctly sets a header like X-Forwarded-Proto).

I ran into this problem when I updated a project hosted behind AWS ELB load balancer and gunicorn to Django 4.0, and the CSRF origin checking for the Django admin stopped working in a staging environment, with the message CSRF verification failed. Request aborted.. I could not figure out what was going on using the documentation and ended up finding the root cause through a stackoverflow answer which pointed out that the origin header is compared against a string constructed of the host, prefixed by either http or https based on the result of request.is_secure()

In my case, the proxy setup was forwarding requests over HTTP, so is_secure() was false and CSRF was comparing the origin https://subdomain.my-domain.com against "host" http://subdomain.my-domain.com. It seems like the best solution here is to use SECURE_PROXY_SSL_HEADER to allow Django to determine if the client is using HTTPS or not, and use the "host" string https://subdomain.my-domain.com . Looking at the referenced stackoverflow thread, this is a recurring problem for users updating to Django 4.0 and many end up with the sub-optimal solution of adding the origin with https to CSRF_ALLOWED_ORIGINS explicitly.

Change History (3)

in reply to:  description comment:1 by Mariusz Felisiak, 14 months ago

Cc: Florian Apolloner added
Easy pickings: unset
Resolution: wontfix
Status: newclosed
Summary: Documenting CSRF_TRUSTED_ORIGINS relation to SECURE_PROXY_SSL_HEADER could prevent misconfiguration when proxying HTTPs over HTTPDocument CSRF_TRUSTED_ORIGINS relation to SECURE_PROXY_SSL_HEADER.

Replying to jeroenmuller:

It might be useful to add a note or warning below https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS explaining that it should only be neccessary to configure this if you are actually making requests across subdomains, and in other cases setting up SECURE_PROXY_SSL_HEADER might be a more appropriate solution (as long as the proxy correctly sets a header like X-Forwarded-Proto).

Using SECURE_PROXY_SSL_HEADER must be an informed decision as it may cause security issues. This is not something we would freely document as a default solution, especially, since it's only a solution for this particular setup where you have a trusted proxy that changes the protocol. I'm skeptical, we cannot document all setting configurations.

comment:2 by Florian Apolloner, 14 months ago

I would be okay with adding documentation for this if it is a recurring issue as long as it does not explicitly refer to SECURE_PROXY_SSL_HEADER but is more like something along the lines of:

If you are seeing CSRF failures on HTTPS sites, it might be possible that your webserver/loadbalancer does not pass on the information that the site is exposed via HTTPS. Please consult the documentation of your webserver/loadbalancer on how to properly configure your site for HTTPS.

We could add "(this might include configuring SECURE_PROXY_SSL_HEADER)" at the end.

comment:3 by Klaas van Schelven, 7 weeks ago

When the CSRF origin check fails, the documentation points in the direction of adding that origin to CSRF_ALLOWED_ORIGINS. However, as far as I understand this should only be neccessary if there are actually cross-origin requests.

I can second this:

The documentation recommends this, as does "the internet" (top-voted answers on Stack Overflow), and pretty much everyone and their dog's blog. Rarely is there any mention that setting this should in fact only be required when you're doing anything cross-origin.

Using SECURE_PROXY_SSL_HEADER must be an informed decision as it may cause security issues.

Yes. But: adding random stuff to CSRF_ALLOWED_ORIGINS should also be an informed decision.

I found it useful to instead push to understanding the problem before proceeding, by getting more verbose error messages from your middleware. Not the entire answer, but yet another puzzle piece.

I'm not pushi

Note: See TracTickets for help on using tickets.
Back to Top