Opened 6 years ago
Closed 6 years ago
#30285 closed Bug (wontfix)
The domain in broken link emails can be spoofed
Reported by: | orlnub123 | Owned by: | nobody |
---|---|---|---|
Component: | Core (Other) | Version: | dev |
Severity: | Normal | Keywords: | middleware |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When using BrokenLinkEmailsMiddleware, if an incoming request with a spoofed HTTP Host header 404s it'll use the spoofed header in the email subject.
This isn't a big issue because the HTTP Host header gets validated against settings.ALLOWED_HOSTS, so it's only applicable on sites with multiple domains or with multiple settings.ALLOWED_HOSTS values.
Here's a demo on a site with multiple settings.ALLOWED_HOSTS values:
We start the server.
[orlnub123@orlnub123 mysite]$ ./manage.py runserver Performing system checks... System check identified no issues (0 silenced). March 24, 2019 - 05:38:46 Django version 2.1.7, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
Then send a normal request. The referer header here is important; without it the email won't get sent.
[orlnub123@orlnub123 mysite]$ curl -H 'Referer: http://example.com/referrer' -w '\n' localhost:8000 <h1>Not Found</h1><p>The requested resource was not found on this server.</p>
We get the email; everything looks good.
Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Django] Broken link on localhost:8000 From: root@localhost To: john@example.com Date: Sun, 24 Mar 2019 05:38:49 -0000 Message-ID: <155340592942.14004.17031704219271235623@orlnub123.localdomain> Referrer: http://example.com/referrer Requested URL: / User agent: curl/7.64.0 IP address: 127.0.0.1 ------------------------------------------------------------------------------- [24/Mar/2019 05:38:49] "GET / HTTP/1.1" 404 77
We send another request; this time with a spoofed host header.
[orlnub123@orlnub123 mysite]$ curl -H 'Referer: http://example.com/referrer' -H 'Host: example.com' -w '\n' localhost:8000 <h1>Not Found</h1><p>The requested resource was not found on this server.</p>
Oh no! The subject contains our spoofed header and presents the link as an internal one.
Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Django] Broken INTERNAL link on example.com From: root@localhost To: john@example.com Date: Sun, 24 Mar 2019 05:38:59 -0000 Message-ID: <155340593990.14004.12227248404736375101@orlnub123.localdomain> Referrer: http://example.com/referrer Requested URL: / User agent: curl/7.64.0 IP address: 127.0.0.1 ------------------------------------------------------------------------------- [24/Mar/2019 05:38:59] "GET / HTTP/1.1" 404 77
I've fixed it by replacing the request.get_host()
call with get_current_site(request).domain
. This approach falls back to using request.get_host()
internally on sites that don't use the sites framework. It isn't perfect, but it replicates what many other components do.
Grrr, happy to discuss options but, I think we have to say
wontfix
here: we can't introduce a dependency oncontrib.sites
inmiddleware.common
.If it weren't for that, I'd probably say, "It's a bit tenuous, but OK, if you're going to fix it". So, question, any fix that doesn't depend on the sites framework?
(Given that the only spoof-able domains must be in
ALLOWED_HOSTS
and the affected function ismail_managers()
I can't see that we need to take Herculean measures here...)