Prevented reverse() from generating URLs pointing to other hosts.

This is a security fix. Disclosure following shortly.
This commit is contained in:
Florian Apolloner 2014-07-17 21:59:28 +02:00 committed by Tim Graham
parent ec71191be0
commit 28e765810d
6 changed files with 50 additions and 1 deletions

View File

@ -456,7 +456,11 @@ class RegexURLResolver(LocaleRegexProvider):
# safe characters from `pchar` definition of RFC 3986 # safe characters from `pchar` definition of RFC 3986
candidate_subs = dict((k, urlquote(v, safe=RFC3986_SUBDELIMS + str('/~:@'))) candidate_subs = dict((k, urlquote(v, safe=RFC3986_SUBDELIMS + str('/~:@')))
for (k, v) in candidate_subs.items()) for (k, v) in candidate_subs.items())
return candidate_pat % candidate_subs url = candidate_pat % candidate_subs
# Don't allow construction of scheme relative urls.
if url.startswith('//'):
url = '/%%2F%s' % url[2:]
return url
# lookup_view can be URL label, or dotted path, or callable, Any of # lookup_view can be URL label, or dotted path, or callable, Any of
# these can be passed in at the top, but callables are not friendly in # these can be passed in at the top, but callables are not friendly in
# error messages. # error messages.

View File

@ -5,3 +5,16 @@ Django 1.4.14 release notes
*Under development* *Under development*
Django 1.4.14 fixes several security issues in 1.4.13. Django 1.4.14 fixes several security issues in 1.4.13.
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts
=======================================================================================
In certain situations, URL reversing could generate scheme-relative URLs (URLs
starting with two slashes), which could unexpectedly redirect a user to a
different host. An attacker could exploit this, for example, by redirecting
users to a phishing site designed to ask for user's passwords.
To remedy this, URL reversing now ensures that no URL starts with two slashes
(//), replacing the second slash with its URL encoded counterpart (%2F). This
approach ensures that semantics stay the same, while making the URL relative to
the domain and not to the scheme.

View File

@ -5,3 +5,16 @@ Django 1.5.9 release notes
*Under development* *Under development*
Django 1.5.9 fixes several security issues in 1.5.8. Django 1.5.9 fixes several security issues in 1.5.8.
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts
=======================================================================================
In certain situations, URL reversing could generate scheme-relative URLs (URLs
starting with two slashes), which could unexpectedly redirect a user to a
different host. An attacker could exploit this, for example, by redirecting
users to a phishing site designed to ask for user's passwords.
To remedy this, URL reversing now ensures that no URL starts with two slashes
(//), replacing the second slash with its URL encoded counterpart (%2F). This
approach ensures that semantics stay the same, while making the URL relative to
the domain and not to the scheme.

View File

@ -6,6 +6,19 @@ Django 1.6.6 release notes
Django 1.6.6 fixes several security issues and bugs in 1.6.5. Django 1.6.6 fixes several security issues and bugs in 1.6.5.
:func:`~django.core.urlresolvers.reverse()` could generate URLs pointing to other hosts
=======================================================================================
In certain situations, URL reversing could generate scheme-relative URLs (URLs
starting with two slashes), which could unexpectedly redirect a user to a
different host. An attacker could exploit this, for example, by redirecting
users to a phishing site designed to ask for user's passwords.
To remedy this, URL reversing now ensures that no URL starts with two slashes
(//), replacing the second slash with its URL encoded counterpart (%2F). This
approach ensures that semantics stay the same, while making the URL relative to
the domain and not to the scheme.
Bugfixes Bugfixes
======== ========

View File

@ -152,6 +152,9 @@ test_data = (
('defaults', '/defaults_view2/3/', [], {'arg1': 3, 'arg2': 2}), ('defaults', '/defaults_view2/3/', [], {'arg1': 3, 'arg2': 2}),
('defaults', NoReverseMatch, [], {'arg1': 3, 'arg2': 3}), ('defaults', NoReverseMatch, [], {'arg1': 3, 'arg2': 3}),
('defaults', NoReverseMatch, [], {'arg2': 1}), ('defaults', NoReverseMatch, [], {'arg2': 1}),
# Security tests
('security', '/%2Fexample.com/security/', ['/example.com'], {}),
) )

View File

@ -75,4 +75,7 @@ with warnings.catch_warnings(record=True):
(r'defaults_view2/(?P<arg1>[0-9]+)/', defaults_view, {'arg2': 2}, 'defaults'), (r'defaults_view2/(?P<arg1>[0-9]+)/', defaults_view, {'arg2': 2}, 'defaults'),
url('^includes/', include(other_patterns)), url('^includes/', include(other_patterns)),
# Security tests
url('(.+)/security/$', empty_view, name='security'),
) )