#36514: Improve ALLOWED_HOSTS error message: show both values
-------------------------------------+-------------------------------------
Reporter: Klaas van Schelven | Type:
| Uncategorized
Status: new | Component:
| Uncategorized
Version: 5.2 | Severity: Normal
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
When Django rejects a request because the Host header doesn't match
ALLOWED_HOSTS, the resulting error message shows
only the incoming header value:
Invalid HTTP_HOST header: 'localhost:8000'. You may need to add
'localhost' to ALLOWED_HOSTS.
This makes it harder to determine whether the problem is a misconfigured
proxy (not setting the correct Host) or simply
a missing hostname in ALLOWED_HOSTS. In many cases, the advice to "add
localhost" is actively unhelpful: production
deployments rarely serve requests at localhost, and the real fix is
usually to configure the proxy correctly.
I’ve implemented a more helpful version of this logic in Bugsink (a Django
app installed by users who may not be Django
developers). I describe that implementation in more detail in [this blog
post about improving Django’s ALLOWED_HOSTS error
messages](
https://www.bugsink.com/blog/better-allowed-hosts/#better-error-
messages).
In the "bugsink approach" the error:
* shows the actual Host header and the configured ALLOWED_HOSTS
* suggests the likely cause
* avoids pointing users towards "add localhost" as the default fix
Some of what I did in Bugsink likely goes beyond what Django should adopt
by default (e.g. showing the error in the
browser), but the idea of displaying both values (the incoming host and
the configured list) would be a broadly useful
change on its own.
If desired, the message could also give more specific advice depending on
the values (e.g. distinguish between loopback
and public domains), but that can be considered separately.
== Security considerations ==
Showing both the incoming Host header and the configured ALLOWED_HOSTS
reveals limited information:
* The Host header is attacker-controlled — the client already knows what
they sent.
* _or_ The Host header is simply a misconfiguration (in which case it's
on-broken-deploy only)
* ALLOWED_HOSTS reveals the expected hostname(s). In most deployments,
this is already visible in the TLS certificate.
--
Ticket URL: <
https://code.djangoproject.com/ticket/36514>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.