Security releases issued
Today the Django team is issuing multiple releases -- Django 1.3.6, Django 1.4.4, and Django 1.5 release candidate 2 -- as part of our security process.
These releases remedy multiple issues reported to us, and involve one important end-user-visible change, so please read these notes carefully.
Here's a brief summary of each issue and its resolution:
Issue: Host header poisoning: an attacker could cause Django to generate and display URLs that link to arbitrary domains. This could be used as part of a phishing attack. These releases fix this problem by introducing a new setting, ALLOWED_HOSTS, which specifies a whitelist of domains your site is known to respond to.
Important: by default Django 1.3.6 and 1.4.4 set ALLOWED_HOSTS to allow all hosts. This means that to actually fix the security vulnerability you should define this setting yourself immediately after upgrading.
Issue: Formset denial-of-service: an attacker can abuse Django's tracking of the number of forms in a formset to cause a denial-of-service attack. This has been fixed by adding a default maximum number of forms of 1,000. You can still manually specify a bigger max_num, if you wish, but 1,000 should be enough for anyone.
Issue: XML attacks: Django's serialization framework was vulnerable to attacks via XML entity expansion and external references; this is now fixed. However, if you're parsing arbitrary XML in other parts of your application, we recommend you look into the defusedxml Python packages which remedy this anywhere you parse XML, not just via Django's serialization framework.
Issue: Data leakage via admin history log: Django's admin interface could expose supposedly-hidden information via its history log. This has been fixed.
For more details, read on.
Issue: Host header poisoning
Several previous Django security releases have attempted to address persistent issues with the HTTP Host header. Django contains code -- and some functionality shipped with Django itself makes use of that code -- for constructing a fully-qualified URL based on the incoming HTTP request. Depending on configuration, this makes use of the Host header, and so an attacker who can cause a Django application to respond to arbitrary Host headers can cause Django to generate, and display to end users, URLs on arbitrary domains.
Previous iterations of this issue (see CVE-2011-4139 and CVE-2012-4520) have focused on tightening Django's parsing of Host headers, to eliminate various means by which attackers -- using techniques such as username/password pairs in their submitted Host header -- could exploit this.
Ultimately, however, Django alone cannot ensure that an attacker is unable to submit, and cause Django to accept, arbitrary Host headers. Properly securing this in a deployed Django instance additionally requires configuration of the web server, and both the configuration and the achievable level of security vary with the server being used.
In light of this, the get_host() method of django.http.HttpRequest will now validate the Host header against a new setting, ALLOWED_HOSTS. This setting is a list of strings (by default, an empty list) corresponding to acceptable values for the header, with some support for wildcards.
Code which does not use get_host(), or Django configurations which can determine the current hostname without recourse to HTTP headers (i.e., when Django's sites framework is enabled) will not be affected by this change.
Since this is hardening/tightening of a previous issue, it does not have a new CVE number.
Issue: XML attacks
Django's serialization framework includes support for serializing to, and deserializing from, XML. Django's XML deserialization is vulnerable to entity-expansion and external-entity/DTD attacks.
To remedy this, Django's XML deserializer no longer allows DTDs, performs entity expansion, or fetches external entities/DTDs. Note that this only protects Django's XML serialization framework; if your application parses XML, we recommend you look into the defusedxml Python packages which remedy this for Python itself.
Because this issue also affects Python's XML libraries, it is covered by Python's CVE-2013-1664 and CVE-2013-1665.
Issue: Data leakage via admin history log
Django's bundled administrative interface keeps a log of actions taken, preserving the history of any object which is exposed through the admin interface. This history view does not perform any permission checks beyond confirming that the user has access to the administrative interface; as such, any user with admin access can view the history of any object accessible in the admin interface, and see summaries of each change made to an object.
To remedy this, the admin history view for an object will now perform the same permission checks as other admin views for the same object.
This issue is CVE-2013-0305.
Issue: Formset denial-of-service
Django's form library includes tools for generating formsets -- multiple instances of a single form, to be submitted simultaneously (e.g., for mass editing/updating of similar objects). Formsets allow a parameter, max_num, specifying the maximum number of individual forms which may be displayed. A hidden input in the formset then specifies the number of forms being submitted.
Django accepts the submitted hidden value, and attempts to instantiate that many form objects. Sufficiently large values will result in extreme memory consumption; values exceeding sys.maxint will, in this case, result in an HTTP 500 response (due to an uncaught OverflowError from the over-large value). In the former case, the result is an effective denial-of-service attack. In the latter, an attacker can cause arbitrary server errors.
To resolve this, Django will now supply a (suitably large) default value for the maximum number of forms, which will be used when max_num is not supplied. Application developers can still manually specify max_num to suit the needs of their applications, but absent this the default value -- 1000 -- will ensure that attackers cannot cause overflow errors or excessive memory consumption.
This issue is CVE-2013-0306.
The issues described above affect the following versions of Django:
- Django master development branch
- Django 1.5 release branch (soon to become Django 1.5)
- Django 1.4 release branch
- Django 1.3 release branch
Patches have been applied to Django's master development branch, and to the 1.5, 1.4 and 1.3 release branches, which resolve the issues described above. The patches may be obtained directly from the following changesets.
On the development master branch:
On the Django 1.5 release branch:
On the Django 1.4 release branch:
On the Django 1.3 release branch:
The following new releases have been issued:
Followup on the Host header issue again came from James Kettle. The XML vulnerability was reported to us by Michael Koziarski of Rails. The essentials of the patch came from Christian Heimes. The admin information leakage issue was reported by Orange Tsai. The formset validation issue was reported by Mozilla.
General notes regarding security reporting
As always, we ask that potential security issues be reported via private email to email@example.com, and not via Django's Trac instance or the django-developers list. Please see our security policies for further information.
Posted by James Bennett on February 19, 2013