# Forwarded headers CSRF hints

**URL:** <https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616>\
**Category:** Django Internals\
**Created:** [March 2, 2024, 3:49am UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616 "2024-03-02T03:49:48Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryanhiebert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ryanhiebert/32/64_2.png) [@ryanhiebert](https://forum.djangoproject.com/u/ryanhiebert)\
**Post date:** [March 2, 2024, 3:49am UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/1 "2024-03-02T03:49:49Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [March 2, 2024, 9:44am UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/2 "2024-03-02T09:44:53Z")

</div>

Thanks for raising this @ryanhiebert. I’ve thought about (and [faced](https://noumenal.es/notes/til/django/csrf-trusted-origins/)) 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. 🤔 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. 😉

---

<div class="post-metadata">

**Author:** ![CodenameTim](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/codenametim/32/31507_2.png) [@CodenameTim](https://forum.djangoproject.com/u/CodenameTim)\
**Post date:** [March 2, 2024, 9:47am UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/3 "2024-03-02T09:47:39Z")

</div>

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.

> [@CSRF invalidation improvements](https://forum.djangoproject.com/t/csrf-invalidation-improvements/25572):
>
> The exception flow for CSRF issues is a bit difficult. I think we can make it easier for developers to determine the root cause of a CSRF invalidation by doing the following: Log a detailed explanation of the error. For example when a CSRF token is missing from the headers, the error message presented to the user is “CSRF token missing.” This doesn’t explain where it’s missing or how it could potentially be added in. For new Django devs this is a very cryptic message. (less sure) Use a unique …

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [March 2, 2024, 9:52am UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/4 "2024-03-02T09:52:01Z")

</div>

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…)

---

<div class="post-metadata">

**Author:** ![ryanhiebert](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ryanhiebert/32/64_2.png) [@ryanhiebert](https://forum.djangoproject.com/u/ryanhiebert)\
**Post date:** [March 2, 2024, 1:25pm UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/5 "2024-03-02T13:25:36Z")

</div>

> [@carltongibson](#):
>
> 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 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.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 2, 2024, 3:10pm UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/6 "2024-03-02T15:10:22Z")

</div>

> [@ryanhiebert](#):
>
> But I have wondered how wide the variance of usage is 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/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.

---

<div class="post-metadata">

**Author:** ![carltongibson](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/carltongibson/32/267_2.png) [@carltongibson](https://forum.djangoproject.com/u/carltongibson)\
**Post date:** [March 2, 2024, 6:24pm UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/7 "2024-03-02T18:24:23Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![sarahboyce](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sarahboyce/32/12734_2.png) [@sarahboyce](https://forum.djangoproject.com/u/sarahboyce)\
**Post date:** [April 25, 2024, 2:34pm UTC](https://forum.djangoproject.com/t/forwarded-headers-csrf-hints/28616/8 "2024-04-25T14:34:30Z")

</div>

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)](https://code.djangoproject.com/ticket/35328)  
With a PR: [Fixed #35328 - Improved debug messaging behind proxies. by ryanhiebert · Pull Request #18014 · django/django (github.com)](https://github.com/django/django/pull/18014)

Further comments and reviews are welcome 👍
