Forwarded headers CSRF hints

I’ve been considering options for how we can make it easier to get things configured correctly with the CSRF middleware. Recently I set up a new project, and the message I got (in debug mode) made me think that I needed to add the domain that it was serving from to the CSRF_TRUSTED_ORIGINS, when really I needed to configure the appropriate settings so that Django would understand the headers that the serving proxy was sending.

Here are some possibilities that seem feasible to me:

  1. Include both the rejected origin as well as the expected server (trusted origin) in the detailed error message, so that you can see that it is wrong.
  2. Include some pointers in the help text in DEBUG mode.
  3. If we detect that common proxy headers are sent on the request but are not configured, we might even be able to give specific recomendations on the extended CSRF help page.

I also had the idea of trying to make the settings related the the X-Forwarded-* headers simpler to start with, such as by consolidating into one setting like TRUST_PROXY_HEADERS, but I’m not sure yet if I think that’s actually feasible and wise.

Thanks for raising this @ryanhiebert. I’ve thought about (and faced) this issue a fair bit.

I think the main issue is that request.is_secure() is quite tricky to configure correctly, given that most applications do SSL termination at the frontend load-balancer, rather than at the WSGI server. (This means that WSGI reports that it’s not serving under SSL, and then request.is_secure() returns False. The way around this is to configure SECURE_PROXY_SSL_HEADER, but that can be tricky to even know about, and tricky to get right, depending on your hosting setup.

I’d like to see a simpler short-circuit setting here. Something like APPLICATION_USES_HTTP — which should likely default to True in this day and age — almost every application is using HTTPS now — that if True has request.is_secure() return True before using the existing logic. (Maybe the default should be not DEBUG, because almost every app is not using HTTPS in development.)

You’d set APPLICATION_USES_HTTP to False if you had cases where you weren’t using HTTPS, and the existing SECURE_PROXY_SSL_HEADER check could remain for (existing and) mixed cases.

But a much clearer on/off toggle is what we need here, I believe.

Whether or not other settings could also defer to the proposed APPLICATION_USES_HTTP I haven’t really considered, but possibly so. :thinking: I see a lot of posts here about CSRF Origin errors. I don’t recall seeing so many about other things.

That’s my tuppence worth. :wink:

1 Like

I want to link the other conversation on this to here as well. I’m in support of tweaking how csrf is handled to be more clear on what should be changed.

1 Like

Yes, I realise I didn’t respond directly to @ryanhiebert’s suggestion. Improving the CSRF errors, so they’re easier to debug is also worth pursuing!

(But I think most issue threads I see are about the Origin check when you come to deploy…)

1 Like

I find that particular setting difficult mainly because it’s not in parity with other forwarded headers settings. I’m thinking to attempt to give particular suggestions that can be copy-pasted into settings, and that works even with the existing settings. But I have wondered how wide the variance of usage is for that header. As you point out, most applications are via HTTP, so it feels cumbersome compared to something like USE_X_FORWARDED_PROTO and detecting that https is a secure option for that header.

I can identify three different variations that I encounter. It can vary by server / firewall / proxy / load balancer.

The X_FORWARDED_PROTO is a de-facto “standard”, not something required by any of the applicable RFCs. The Forwarded header may become a true standard, but there are a lot of legacy servers out there that aren’t likely to be changed in the near future.

1 Like

Also it ends up being a list (sometimes) if you go through multiple layers. So there’s no easy one value to know to respect. It really does depend on your setup.

To make sure those in this discussion and others that land here know what is going on.
This has a ticket: #35328 (Improve CSRF Origin checking messaging) – Django (djangoproject.com)
With a PR: Fixed #35328 - Improved debug messaging behind proxies. by ryanhiebert · Pull Request #18014 · django/django (github.com)

Further comments and reviews are welcome :+1: