[Django] #30285: The domain in broken link emails can be spoofed

4 views
Skip to first unread message

Django

unread,
Mar 24, 2019, 2:23:09 AM3/24/19
to django-...@googlegroups.com
#30285: The domain in broken link emails can be spoofed
----------------------------------------+----------------------------
Reporter: orlnub123 | Owner: nobody
Type: Bug | Status: new
Component: Core (Other) | Version: master
Severity: Normal | Keywords: middleware
Triage Stage: Unreviewed | Has patch: 1
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
----------------------------------------+----------------------------
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: jo...@example.com
Date: Sun, 24 Mar 2019 05:38:49 -0000
Message-ID:
<155340592942.14004....@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: jo...@example.com
Date: Sun, 24 Mar 2019 05:38:59 -0000
Message-ID:
<155340593990.14004....@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.

--
Ticket URL: <https://code.djangoproject.com/ticket/30285>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Mar 28, 2019, 5:03:18 AM3/28/19
to django-...@googlegroups.com
#30285: The domain in broken link emails can be spoofed
------------------------------+--------------------------------------
Reporter: orlnub123 | Owner: nobody
Type: Bug | Status: closed

Component: Core (Other) | Version: master
Severity: Normal | Resolution: wontfix

Keywords: middleware | Triage Stage: Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Changes (by Carlton Gibson):

* status: new => closed
* resolution: => wontfix


Comment:

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

--
Ticket URL: <https://code.djangoproject.com/ticket/30285#comment:1>

Reply all
Reply to author
Forward
0 new messages