Loading django/utils/http.py +8 −1 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import re import sys import urllib import urlparse import unicodedata from email.utils import formatdate from django.utils.datastructures import MultiValueDict Loading Loading @@ -232,9 +233,10 @@ def is_safe_url(url, host=None): Always returns ``False`` on an empty url. """ if url is not None: url = url.strip() if not url: return False url = url.strip() # Chrome treats \ completely as / url = url.replace('\\', '/') # Chrome considers any URL with more than two slashes to be absolute, but Loading @@ -248,5 +250,10 @@ def is_safe_url(url, host=None): # allow this syntax. if not url_info[1] and url_info[0]: return False # Forbid URLs that start with control characters. Some browsers (like # Chrome) ignore quite a few control characters at the start of a # URL and might consider the URL as scheme relative. if unicodedata.category(unicode(url[0]))[0] == 'C': return False return (not url_info[1] or url_info[1] == host) and \ (not url_info[0] or url_info[0] in ['http', 'https']) docs/releases/1.4.20.txt +19 −0 Original line number Diff line number Diff line Loading @@ -5,3 +5,22 @@ Django 1.4.20 release notes *March 18, 2015* Django 1.4.20 fixes one security issue in 1.4.19. Mitigated possible XSS attack via user-supplied redirect URLs ============================================================= Django relies on user input in some cases (e.g. :func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) to redirect the user to an "on success" URL. The security checks for these redirects (namely ``django.utils.http.is_safe_url()``) accepted URLs with leading control characters and so considered URLs like ``\x08javascript:...`` safe. This issue doesn't affect Django currently, since we only put this URL into the ``Location`` response header and browsers seem to ignore JavaScript there. Browsers we tested also treat URLs prefixed with control characters such as ``%08//example.com`` as relative paths so redirection to an unsafe target isn't a problem either. However, if a developer relies on ``is_safe_url()`` to provide safe redirect targets and puts such a URL into a link, they could suffer from an XSS attack as some browsers such as Google Chrome ignore control characters at the start of a URL in an anchor ``href``. tests/regressiontests/utils/http.py +3 −1 Original line number Diff line number Diff line Loading @@ -98,7 +98,9 @@ class TestUtilsHttp(unittest.TestCase): 'http:\/example.com', 'http:/\example.com', 'javascript:alert("XSS")' '\njavascript:alert(x)'): '\njavascript:alert(x)', '\x08//example.com', '\n'): self.assertFalse(http.is_safe_url(bad_url, host='testserver'), "%s should be blocked" % bad_url) for good_url in ('/view/?param=http://example.com', '/view/?param=https://example.com', Loading Loading
django/utils/http.py +8 −1 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import re import sys import urllib import urlparse import unicodedata from email.utils import formatdate from django.utils.datastructures import MultiValueDict Loading Loading @@ -232,9 +233,10 @@ def is_safe_url(url, host=None): Always returns ``False`` on an empty url. """ if url is not None: url = url.strip() if not url: return False url = url.strip() # Chrome treats \ completely as / url = url.replace('\\', '/') # Chrome considers any URL with more than two slashes to be absolute, but Loading @@ -248,5 +250,10 @@ def is_safe_url(url, host=None): # allow this syntax. if not url_info[1] and url_info[0]: return False # Forbid URLs that start with control characters. Some browsers (like # Chrome) ignore quite a few control characters at the start of a # URL and might consider the URL as scheme relative. if unicodedata.category(unicode(url[0]))[0] == 'C': return False return (not url_info[1] or url_info[1] == host) and \ (not url_info[0] or url_info[0] in ['http', 'https'])
docs/releases/1.4.20.txt +19 −0 Original line number Diff line number Diff line Loading @@ -5,3 +5,22 @@ Django 1.4.20 release notes *March 18, 2015* Django 1.4.20 fixes one security issue in 1.4.19. Mitigated possible XSS attack via user-supplied redirect URLs ============================================================= Django relies on user input in some cases (e.g. :func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`) to redirect the user to an "on success" URL. The security checks for these redirects (namely ``django.utils.http.is_safe_url()``) accepted URLs with leading control characters and so considered URLs like ``\x08javascript:...`` safe. This issue doesn't affect Django currently, since we only put this URL into the ``Location`` response header and browsers seem to ignore JavaScript there. Browsers we tested also treat URLs prefixed with control characters such as ``%08//example.com`` as relative paths so redirection to an unsafe target isn't a problem either. However, if a developer relies on ``is_safe_url()`` to provide safe redirect targets and puts such a URL into a link, they could suffer from an XSS attack as some browsers such as Google Chrome ignore control characters at the start of a URL in an anchor ``href``.
tests/regressiontests/utils/http.py +3 −1 Original line number Diff line number Diff line Loading @@ -98,7 +98,9 @@ class TestUtilsHttp(unittest.TestCase): 'http:\/example.com', 'http:/\example.com', 'javascript:alert("XSS")' '\njavascript:alert(x)'): '\njavascript:alert(x)', '\x08//example.com', '\n'): self.assertFalse(http.is_safe_url(bad_url, host='testserver'), "%s should be blocked" % bad_url) for good_url in ('/view/?param=http://example.com', '/view/?param=https://example.com', Loading