[Python-modules-commits] r22801 - in packages/python-django/branches/squeeze/debian (3 files)

hertzog at users.alioth.debian.org hertzog at users.alioth.debian.org
Mon Oct 22 08:32:10 UTC 2012


    Date: Monday, October 22, 2012 @ 08:31:55
  Author: hertzog
Revision: 22801

* Stable security upload:
  https://www.djangoproject.com/weblog/2012/oct/17/security/
  Fixes: CVE-2012-4520
* Add the upstream patch:
  - debian/patches/19_fix_host_header_poisoning.diff
  Closes: #691145

Added:
  packages/python-django/branches/squeeze/debian/patches/19_fix_host_header_poisoning.diff
Modified:
  packages/python-django/branches/squeeze/debian/changelog
  packages/python-django/branches/squeeze/debian/patches/series

Modified: packages/python-django/branches/squeeze/debian/changelog
===================================================================
--- packages/python-django/branches/squeeze/debian/changelog	2012-10-21 09:36:40 UTC (rev 22800)
+++ packages/python-django/branches/squeeze/debian/changelog	2012-10-22 08:31:55 UTC (rev 22801)
@@ -1,3 +1,14 @@
+python-django (1.2.3-3+squeeze4) stable-security; urgency=low
+
+  * Stable security upload:
+    https://www.djangoproject.com/weblog/2012/oct/17/security/
+    Fixes: CVE-2012-4520
+  * Add the upstream patch:
+    - debian/patches/19_fix_host_header_poisoning.diff
+    Closes: #691145
+
+ -- Raphaël Hertzog <hertzog at debian.org>  Mon, 22 Oct 2012 10:19:12 +0200
+
 python-django (1.2.3-3+squeeze3) stable-security; urgency=high
 
   * Stable security upload:

Added: packages/python-django/branches/squeeze/debian/patches/19_fix_host_header_poisoning.diff
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/19_fix_host_header_poisoning.diff	                        (rev 0)
+++ packages/python-django/branches/squeeze/debian/patches/19_fix_host_header_poisoning.diff	2012-10-22 08:31:55 UTC (rev 22801)
@@ -0,0 +1,102 @@
+Description: Fix Host header poisoning
+Origin: upstream, https://github.com/django/django/commit/b45c377f8f488955e0c7069cad3f3dd21910b071/download
+Bug-Debian: http://bugs.debian.org/691145
+
+diff --git a/django/contrib/auth/tests/urls.py b/django/contrib/auth/tests/urls.py
+index 3d76a4e..c01964f 100644
+--- a/django/contrib/auth/tests/urls.py
++++ b/django/contrib/auth/tests/urls.py
+@@ -19,6 +19,7 @@ urlpatterns = urlpatterns + patterns('',
+     (r'^logout/next_page/$', 'django.contrib.auth.views.logout', dict(next_page='/somewhere/')),
+     (r'^remote_user/$', remote_user_auth_view),
+     (r'^password_reset_from_email/$', 'django.contrib.auth.views.password_reset', dict(from_email='staffmember at example.com')),
++    (r'^admin_password_reset/$', 'django.contrib.auth.views.password_reset', dict(is_admin_site=True)),
+     (r'^login_required/$', login_required(password_reset)),
+     (r'^login_required_login_url/$', login_required(password_reset, login_url='/somewhere/')),
+ )
+diff --git a/django/contrib/auth/tests/views.py b/django/contrib/auth/tests/views.py
+index b03489c..046d00d 100644
+--- a/django/contrib/auth/tests/views.py
++++ b/django/contrib/auth/tests/views.py
+@@ -9,6 +9,7 @@ from django.contrib.sites.models import Site, RequestSite
+ from django.contrib.auth.models import User
+ from django.test import TestCase
+ from django.core import mail
++from django.core.exceptions import SuspiciousOperation
+ from django.core.urlresolvers import reverse
+ from django.http import QueryDict
+ 
+@@ -69,6 +70,44 @@ class PasswordResetTest(AuthViewsTestCase):
+         self.assertEqual(len(mail.outbox), 1)
+         self.assertEqual("staffmember at example.com", mail.outbox[0].from_email)
+ 
++    def test_admin_reset(self):
++        "If the reset view is marked as being for admin, the HTTP_HOST header is used for a domain override."
++        response = self.client.post('/admin_password_reset/',
++            {'email': 'staffmember at example.com'},
++            HTTP_HOST='adminsite.com'
++        )
++        self.assertEqual(response.status_code, 302)
++        self.assertEqual(len(mail.outbox), 1)
++        self.assertTrue("http://adminsite.com" in mail.outbox[0].body)
++        self.assertEqual(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email)
++
++    def test_poisoned_http_host(self):
++        "Poisoned HTTP_HOST headers can't be used for reset emails"
++        # This attack is based on the way browsers handle URLs. The colon
++        # should be used to separate the port, but if the URL contains an @,
++        # the colon is interpreted as part of a username for login purposes,
++        # making 'evil.com' the request domain. Since HTTP_HOST is used to
++        # produce a meaningful reset URL, we need to be certain that the
++        # HTTP_HOST header isn't poisoned. This is done as a check when get_host()
++        # is invoked, but we check here as a practical consequence.
++        def test_host_poisoning():
++            self.client.post('/password_reset/',
++                {'email': 'staffmember at example.com'},
++                HTTP_HOST='www.example:dr.frankenstein at evil.tld'
++            )
++        self.assertRaises(SuspiciousOperation, test_host_poisoning)
++        self.assertEqual(len(mail.outbox), 0)
++
++    def test_poisoned_http_host_admin_site(self):
++        "Poisoned HTTP_HOST headers can't be used for reset emails on admin views"
++        def test_host_poisoning():
++            self.client.post('/admin_password_reset/',
++                {'email': 'staffmember at example.com'},
++                HTTP_HOST='www.example:dr.frankenstein at evil.tld'
++            )
++        self.assertRaises(SuspiciousOperation, test_host_poisoning)
++        self.assertEqual(len(mail.outbox), 0)
++
+     def _test_confirm_start(self):
+         # Start by creating the email
+         response = self.client.post('/password_reset/', {'email': 'staffmember at example.com'})
+diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
+index eba83a2..727e916 100644
+--- a/django/contrib/auth/views.py
++++ b/django/contrib/auth/views.py
+@@ -151,7 +151,7 @@ def password_reset(request, is_admin_site=False,
+                 'request': request,
+             }
+             if is_admin_site:
+-                opts = dict(opts, domain_override=request.META['HTTP_HOST'])
++                opts = dict(opts, domain_override=request.get_host())
+             form.save(**opts)
+             return HttpResponseRedirect(post_reset_redirect)
+     else:
+diff --git a/django/http/__init__.py b/django/http/__init__.py
+index 2dfe12e..dddd9a8 100644
+--- a/django/http/__init__.py
++++ b/django/http/__init__.py
+@@ -165,6 +165,11 @@ class HttpRequest(object):
+             server_port = str(self.META['SERVER_PORT'])
+             if server_port != (self.is_secure() and '443' or '80'):
+                 host = '%s:%s' % (host, server_port)
++
++        # Disallow potentially poisoned hostnames.
++        if set(';/?@&=+$,').intersection(host):
++            raise SuspiciousOperation('Invalid HTTP_HOST header: %s' % host)
++
+         return host
+ 
+     def get_full_path(self):

Modified: packages/python-django/branches/squeeze/debian/patches/series
===================================================================
--- packages/python-django/branches/squeeze/debian/patches/series	2012-10-21 09:36:40 UTC (rev 22800)
+++ packages/python-django/branches/squeeze/debian/patches/series	2012-10-22 08:31:55 UTC (rev 22801)
@@ -15,3 +15,4 @@
 16_fix_cross_site_scripting_in_authentication.diff
 17_fix_dos_in_image_validation.diff
 18_fix_dos_via_get_image_dimensions.diff
+19_fix_host_header_poisoning.diff




More information about the Python-modules-commits mailing list