summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrzemysław Suliga <mail@suligap.net>2016-08-19 14:32:21 +0200
committerTim Graham <timograham@gmail.com>2016-08-19 19:16:00 -0400
commit1f68bb5683608ebe1ce47f0c9d37dad9482d1df9 (patch)
tree7882a425ade1cb5cc852d7c890f4409f67629bd9
parent549b90fab33c80d1ba6575d4837ea52d79f70fb1 (diff)
Refs #26902 -- Protected against insecure redirects in set_language().
-rw-r--r--django/views/i18n.py5
-rw-r--r--docs/releases/1.11.txt10
-rw-r--r--tests/view_tests/tests/test_i18n.py17
3 files changed, 25 insertions, 7 deletions
diff --git a/django/views/i18n.py b/django/views/i18n.py
index b3aaccbd33..a6bf8bcff4 100644
--- a/django/views/i18n.py
+++ b/django/views/i18n.py
@@ -37,11 +37,12 @@ def set_language(request):
any state.
"""
next = request.POST.get('next', request.GET.get('next'))
- if (next or not request.is_ajax()) and not is_safe_url(url=next, host=request.get_host()):
+ if ((next or not request.is_ajax()) and
+ not is_safe_url(url=next, host=request.get_host(), require_https=request.is_secure())):
next = request.META.get('HTTP_REFERER')
if next:
next = urlunquote(next) # HTTP_REFERER may be encoded.
- if not is_safe_url(url=next, host=request.get_host()):
+ if not is_safe_url(url=next, host=request.get_host(), require_https=request.is_secure()):
next = '/'
response = http.HttpResponseRedirect(next) if next else http.HttpResponse(status=204)
if request.method == 'POST':
diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt
index 64afe7a841..802a09e6a9 100644
--- a/docs/releases/1.11.txt
+++ b/docs/releases/1.11.txt
@@ -356,12 +356,12 @@ to assign a free port. The ``DJANGO_LIVE_TEST_SERVER_ADDRESS`` environment
variable is no longer used, and as it's also no longer used, the
``manage.py test --liveserver`` option is removed.
-Protection against insecure redirects in :mod:`django.contrib.auth` views
--------------------------------------------------------------------------
+Protection against insecure redirects in :mod:`django.contrib.auth` and ``i18n`` views
+--------------------------------------------------------------------------------------
-``LoginView`` and ``LogoutView`` (and the deprecated function-based equivalents)
-protect users from being redirected to non-HTTPS ``next`` URLs when the app
-is running over HTTPS.
+``LoginView``, ``LogoutView`` (and the deprecated function-based equivalents),
+and :func:`~django.views.i18n.set_language` protect users from being redirected
+to non-HTTPS ``next`` URLs when the app is running over HTTPS.
Miscellaneous
-------------
diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py
index e1cf44782d..ae56990fe6 100644
--- a/tests/view_tests/tests/test_i18n.py
+++ b/tests/view_tests/tests/test_i18n.py
@@ -54,6 +54,23 @@ class I18NTests(TestCase):
self.assertEqual(response.url, '/')
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
+ def test_setlang_http_next(self):
+ """
+ The set_language view only redirects to the 'next' argument if it is
+ "safe" and its scheme is https if the request was sent over https.
+ """
+ lang_code = self._get_inactive_language_code()
+ non_https_next_url = 'http://testserver/redirection/'
+ post_data = dict(language=lang_code, next=non_https_next_url)
+ # Insecure URL in POST data.
+ response = self.client.post('/i18n/setlang/', data=post_data, secure=True)
+ self.assertEqual(response.url, '/')
+ self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
+ # Insecure URL in HTTP referer.
+ response = self.client.post('/i18n/setlang/', secure=True, HTTP_REFERER=non_https_next_url)
+ self.assertEqual(response.url, '/')
+ self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
+
def test_setlang_redirect_to_referer(self):
"""
The set_language view redirects to the URL in the referer header when