diff -Nru python-django-1.8.7/debian/changelog python-django-1.8.7/debian/changelog --- python-django-1.8.7/debian/changelog 2016-09-27 14:10:04.000000000 +0000 +++ python-django-1.8.7/debian/changelog 2016-10-31 13:22:27.000000000 +0000 @@ -1,3 +1,19 @@ +python-django (1.8.7-1ubuntu8.1) yakkety-security; urgency=medium + + * SECURITY UPDATE: user with hardcoded password created when running + tests on Oracle + - debian/patches/CVE-2016-9013.patch: remove hardcoded password in + django/db/backends/oracle/creation.py, added note to + docs/ref/settings.txt. + - CVE-2016-9013 + * SECURITY UPDATE: DNS rebinding vulnerability when DEBUG=True + - debian/patches/CVE-2016-9014.patch: properly check ALLOWED_HOSTS in + django/http/request.py, updated docs/ref/settings.txt, added test to + tests/requests/tests.py. + - CVE-2016-9014 + + -- Marc Deslauriers Mon, 31 Oct 2016 09:22:27 -0400 + python-django (1.8.7-1ubuntu8) yakkety; urgency=medium * SECURITY UPDATE: CSRF protection bypass on a site with Google Analytics diff -Nru python-django-1.8.7/debian/patches/CVE-2016-9013.patch python-django-1.8.7/debian/patches/CVE-2016-9013.patch --- python-django-1.8.7/debian/patches/CVE-2016-9013.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-django-1.8.7/debian/patches/CVE-2016-9013.patch 2016-10-31 13:22:15.000000000 +0000 @@ -0,0 +1,76 @@ +commit 70f99952965a430daf69eeb9947079aae535d2d0 +Author: Marti Raudsepp +Date: Mon Oct 24 15:22:00 2016 -0400 + + [1.8.x] Fixed CVE-2016-9013 -- Generated a random database user password when running tests on Oracle. + + This is a security fix. + +diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py +index b7373e8..28475a6 100644 +--- a/django/db/backends/oracle/creation.py ++++ b/django/db/backends/oracle/creation.py +@@ -4,10 +4,10 @@ import time + from django.conf import settings + from django.db.backends.base.creation import BaseDatabaseCreation + from django.db.utils import DatabaseError ++from django.utils.crypto import get_random_string + from django.utils.six.moves import input + + TEST_DATABASE_PREFIX = 'test_' +-PASSWORD = 'Im_a_lumberjack' + + + class DatabaseCreation(BaseDatabaseCreation): +@@ -188,7 +188,11 @@ class DatabaseCreation(BaseDatabaseCreation): + ] + # Ignore "user already exists" error when keepdb is on + acceptable_ora_err = 'ORA-01920' if keepdb else None +- self._execute_allow_fail_statements(cursor, statements, parameters, verbosity, acceptable_ora_err) ++ success = self._execute_allow_fail_statements(cursor, statements, parameters, verbosity, acceptable_ora_err) ++ # If the password was randomly generated, change the user accordingly. ++ if not success and self._test_settings_get('PASSWORD') is None: ++ set_password = "ALTER USER %(user)s IDENTIFIED BY %(password)s" ++ self._execute_statements(cursor, [set_password], parameters, verbosity) + # Most test-suites can be run without the create-view privilege. But some need it. + extra = "GRANT CREATE VIEW TO %(user)s" + success = self._execute_allow_fail_statements(cursor, [extra], parameters, verbosity, 'ORA-01031') +@@ -263,7 +267,7 @@ class DatabaseCreation(BaseDatabaseCreation): + """ + settings_dict = self.connection.settings_dict + val = settings_dict['TEST'].get(key, default) +- if val is None: ++ if val is None and prefixed: + val = TEST_DATABASE_PREFIX + settings_dict[prefixed] + return val + +@@ -280,7 +284,11 @@ class DatabaseCreation(BaseDatabaseCreation): + return self._test_settings_get('USER', prefixed='USER') + + def _test_database_passwd(self): +- return self._test_settings_get('PASSWORD', default=PASSWORD) ++ password = self._test_settings_get('PASSWORD') ++ if password is None and self._test_user_create(): ++ # Oracle passwords are limited to 30 chars and can't contain symbols. ++ password = get_random_string(length=30) ++ return password + + def _test_database_tblspace(self): + return self._test_settings_get('TBLSPACE', prefixed='USER') +diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt +index 30a2c7d..382ce2e 100644 +--- a/docs/ref/settings.txt ++++ b/docs/ref/settings.txt +@@ -773,7 +773,11 @@ Default: ``None`` + This is an Oracle-specific setting. + + The password to use when connecting to the Oracle database that will be used +-when running tests. If not provided, Django will use a hardcoded default value. ++when running tests. If not provided, Django will generate a random password. ++ ++.. versionchanged:: 1.8.16 ++ ++ Older versions used a hardcoded default password. + + .. setting:: TEST_TBLSPACE + diff -Nru python-django-1.8.7/debian/patches/CVE-2016-9014.patch python-django-1.8.7/debian/patches/CVE-2016-9014.patch --- python-django-1.8.7/debian/patches/CVE-2016-9014.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-django-1.8.7/debian/patches/CVE-2016-9014.patch 2016-10-31 13:22:24.000000000 +0000 @@ -0,0 +1,97 @@ +commit c401ae9a7dfb1a94a8a61927ed541d6f93089587 +Author: Tim Graham +Date: Mon Oct 17 12:14:49 2016 -0400 + + [1.8.x] Fixed CVE-2016-9014 -- Validated Host header when DEBUG=True. + + This is a security fix. + +Index: python-django-1.8.7/django/http/request.py +=================================================================== +--- python-django-1.8.7.orig/django/http/request.py 2016-10-31 09:22:22.391123858 -0400 ++++ python-django-1.8.7/django/http/request.py 2016-10-31 09:22:22.387123813 -0400 +@@ -85,12 +85,13 @@ + if server_port != ('443' if self.is_secure() else '80'): + host = '%s:%s' % (host, server_port) + +- # There is no hostname validation when DEBUG=True +- if settings.DEBUG: +- return host ++ # Allow variants of localhost if ALLOWED_HOSTS is empty and DEBUG=True. ++ allowed_hosts = settings.ALLOWED_HOSTS ++ if settings.DEBUG and not allowed_hosts: ++ allowed_hosts = ['localhost', '127.0.0.1', '[::1]'] + + domain, port = split_domain_port(host) +- if domain and validate_host(domain, settings.ALLOWED_HOSTS): ++ if domain and validate_host(domain, allowed_hosts): + return host + else: + msg = "Invalid HTTP_HOST header: %r." % host +Index: python-django-1.8.7/docs/ref/settings.txt +=================================================================== +--- python-django-1.8.7.orig/docs/ref/settings.txt 2016-10-31 09:22:22.391123858 -0400 ++++ python-django-1.8.7/docs/ref/settings.txt 2016-10-31 09:22:22.387123813 -0400 +@@ -108,14 +108,18 @@ + list, the :meth:`django.http.HttpRequest.get_host()` method will raise + :exc:`~django.core.exceptions.SuspiciousOperation`. + +-When :setting:`DEBUG` is ``True`` or when running tests, host validation is +-disabled; any host will be accepted. Thus it's usually only necessary to set it +-in production. ++When :setting:`DEBUG` is ``True`` and ``ALLOWED_HOSTS`` is empty, the host ++is validated against ``['localhost', '127.0.0.1', '[::1]']``. + + This validation only applies via :meth:`~django.http.HttpRequest.get_host()`; + if your code accesses the ``Host`` header directly from ``request.META`` you + are bypassing this security protection. + ++.. versionchanged:: 1.8.16 ++ ++ In older versions, ``ALLOWED_HOSTS`` wasn't checked if ``DEBUG=True``, but ++ it's now checked to prevent a DNS rebinding attack. ++ + .. setting:: ALLOWED_INCLUDE_ROOTS + + ALLOWED_INCLUDE_ROOTS +Index: python-django-1.8.7/tests/requests/tests.py +=================================================================== +--- python-django-1.8.7.orig/tests/requests/tests.py 2016-10-31 09:22:22.391123858 -0400 ++++ python-django-1.8.7/tests/requests/tests.py 2016-10-31 09:22:22.387123813 -0400 +@@ -672,21 +672,22 @@ + request.get_host() + + @override_settings(DEBUG=True, ALLOWED_HOSTS=[]) +- def test_host_validation_disabled_in_debug_mode(self): +- """If ALLOWED_HOSTS is empty and DEBUG is True, all hosts pass.""" +- request = HttpRequest() +- request.META = { +- 'HTTP_HOST': 'example.com', +- } +- self.assertEqual(request.get_host(), 'example.com') ++ def test_host_validation_in_debug_mode(self): ++ """ ++ If ALLOWED_HOSTS is empty and DEBUG is True, variants of localhost are ++ allowed. ++ """ ++ valid_hosts = ['localhost', '127.0.0.1', '[::1]'] ++ for host in valid_hosts: ++ request = HttpRequest() ++ request.META = {'HTTP_HOST': host} ++ self.assertEqual(request.get_host(), host) + +- # Invalid hostnames would normally raise a SuspiciousOperation, +- # but we have DEBUG=True, so this check is disabled. +- request = HttpRequest() +- request.META = { +- 'HTTP_HOST': "invalid_hostname.com", +- } +- self.assertEqual(request.get_host(), "invalid_hostname.com") ++ # Other hostnames raise a SuspiciousOperation. ++ with self.assertRaises(SuspiciousOperation): ++ request = HttpRequest() ++ request.META = {'HTTP_HOST': 'example.com'} ++ request.get_host() + + @override_settings(ALLOWED_HOSTS=[]) + def test_get_host_suggestion_of_allowed_host(self): diff -Nru python-django-1.8.7/debian/patches/series python-django-1.8.7/debian/patches/series --- python-django-1.8.7/debian/patches/series 2016-09-27 14:10:04.000000000 +0000 +++ python-django-1.8.7/debian/patches/series 2016-10-31 13:22:21.000000000 +0000 @@ -8,3 +8,5 @@ CVE-2016-6186.patch Supported-IPv6-formatted-IPv4-addresses.patch CVE-2016-7401.patch +CVE-2016-9013.patch +CVE-2016-9014.patch