Opened 5 years ago

Closed 5 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.

Change History (1)

comment:1 by Carlton Gibson, 5 years ago

Resolution: wontfix
Status: newclosed

Grrr, happy to discuss options but, I think we have to say wontfix here: we can't introduce a dependency on contrib.sites in middleware.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 is mail_managers() I can't see that we need to take Herculean measures here...)

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