Django 1.4.4 introduced the
ALLOWED_HOSTS setting as implemented in
A list of strings representing the host/domain names that this Django site can serve. This is a security measure to prevent an attacker from poisoning caches and password reset emails with links to malicious hosts by submitting requests with a fake HTTP Host header, which is possible even under many seemingly-safe webserver configurations.
If the host header holds an unknown host and
DEBUG is set to
SuspiciousOperation exception is raised. This results in an HTTP 500 (Internal Server Error) error code which is returned to the client. I believe this was chosen over the HTTP 4xy-class error (Client Error) so that the admins are notified via email (see the Error Reporting docs). This is a good thing if you have misconfigured the
ALLOWED_HOSTS setting and forgot to include some host name that should be usable with the site.
If, however, you are constantly spammed by Django error messages because someone is scanning your website and tries to set a fake
Host header, things get annoying. I posted a bug report on the Django bug tracker, and it looks like this will be handled either in 1.5.1 or at least in 1.6. (I wish to note at this place that I’m very grateful that Django has such a responsive dev team. The first response came in in less than 3 hours after the bug, and the first proposed patch was posted on the same day. Thank you!)
Until Django is properly fixed, I need some workaround that I implemented as a logging filter that prevents
SuspiciousOperation exceptions from being sent via email (it does not change the HTTP 500 into an HTTP 400):
from django.core.exceptions import SuspiciousOperation
exc_value = record.exc_info
if isinstance(exc_value, SuspiciousOperation):
To activate this filter, it must be included in your
settings.py file just like in the logging docs, where I also got the blueprint for the code that is listed above.
I prepared a minimal example project for your convenience. It comes with the filter enabled.
If you’d like to verify that the filter works, do the following:
- Check out the example project and make sure that Django is installed (either globally or in a virtualenv).
- Run the dev server:
python manage.py runserver
- On a second terminal, run the SMTP debugging server built into Python:
sudo python -m smtpd -n -c DebuggingServer localhost:25
(sudo is necessary because port 25 (SMTP default) can only be used by root)
- On a third terminal, check that the main page works:
(should print “Hello, world” to the console)
- Check that changing the Host name leads to an error message, but that no email is sent (look at the terminal that runs the SMTP server, nothing should be printed there):
curl -H "Host: asdfasdf" http://localhost:8000/
- Check that other server errors are sent out as an email (the SMTP debugging server should print the lenghty message):