diff -ur Django-1.1.4/django/http/__init__.py Django-1.1.4/django/http/__init__.py --- Django-1.1.4/django/http/__init__.py 2010-03-02 14:41:39.000000000 -0500 +++ Django-1.1.4/django/http/__init__.py 2012-08-01 18:03:55.283753679 -0400 @@ -3,13 +3,15 @@ from Cookie import BaseCookie, SimpleCookie, CookieError from pprint import pformat from urllib import urlencode -from urlparse import urljoin +#from urlparse import urljoin # PATCHOUT +from urlparse import urljoin, urlparse # PATCHIN try: # The mod_python version is more efficient, so try importing it first. from mod_python.util import parse_qsl except ImportError: from cgi import parse_qsl +from django.core.exceptions import SuspiciousOperation # PATCHIN from django.utils.datastructures import MultiValueDict, ImmutableList from django.utils.encoding import smart_str, iri_to_uri, force_unicode from django.http.multipartparser import MultiPartParser @@ -429,19 +431,31 @@ raise Exception("This %s instance cannot tell its position" % self.__class__) return sum([len(chunk) for chunk in self._container]) -class HttpResponseRedirect(HttpResponse): - status_code = 302 +class HttpResponseRedirectBase(HttpResponse): # PATCHIN + allowed_schemes = ['http', 'https', 'ftp'] # PATCHIN +# PATCHIN + def __init__(self, redirect_to): # PATCHIN + super(HttpResponseRedirectBase, self).__init__() # PATCHIN + parsed = urlparse(redirect_to) # PATCHIN + if parsed[0] and parsed[0] not in self.allowed_schemes: # PATCHIN + raise SuspiciousOperation("Unsafe redirect to URL with scheme '%s'" % parsed[0]) # PATCHIN + self['Location'] = iri_to_uri(redirect_to) # PATCHIN - def __init__(self, redirect_to): - HttpResponse.__init__(self) - self['Location'] = iri_to_uri(redirect_to) +#class HttpResponseRedirect(HttpResponse): # PATCHOUT +class HttpResponseRedirect(HttpResponseRedirectBase): # PATCHIN + status_code = 302 +# # PATCHOUT +# def __init__(self, redirect_to): # PATCHOUT +# HttpResponse.__init__(self) # PATCHOUT +# self['Location'] = iri_to_uri(redirect_to) # PATCHOUT -class HttpResponsePermanentRedirect(HttpResponse): +#class HttpResponsePermanentRedirect(HttpResponse): # PATCHOUT +class HttpResponsePermanentRedirect(HttpResponseRedirectBase): # PATCHIN status_code = 301 - - def __init__(self, redirect_to): - HttpResponse.__init__(self) - self['Location'] = iri_to_uri(redirect_to) +# # PATCHOUT +# def __init__(self, redirect_to): # PATCHOUT +# HttpResponse.__init__(self) # PATCHOUT +# self['Location'] = iri_to_uri(redirect_to) # PATCHOUT class HttpResponseNotModified(HttpResponse): status_code = 304 diff -ur Django-1.1.4/tests/regressiontests/httpwrappers/tests.py Django-1.1.4/tests/regressiontests/httpwrappers/tests.py --- Django-1.1.4/tests/regressiontests/httpwrappers/tests.py 2010-02-14 21:18:15.000000000 -0500 +++ Django-1.1.4/tests/regressiontests/httpwrappers/tests.py 2012-08-01 14:00:35.288121420 -0400 @@ -465,7 +465,12 @@ [u'1', u'2', u'3', u'4'] """ -from django.http import QueryDict, HttpResponse, CompatCookie +from django.core.exceptions import SuspiciousOperation # PATCHIN +from django.http import (QueryDict, HttpResponse, HttpResponseRedirect, # PATCHIN + HttpResponsePermanentRedirect, # PATCHIN + SimpleCookie, BadHeaderError, # PATCHIN + parse_cookie, CompatCookie) # PATCHIN +# from django.http import QueryDict, HttpResponse, CompatCookie # PATCHOUT from django.test import TestCase @@ -502,6 +507,18 @@ c2 = CompatCookie() c2.load(c.output()) self.assertEqual(c['test'].value, c2['test'].value) +# PATCHIN + def test_unsafe_redirects(self): # PATCHIN + bad_urls = [ # PATCHIN + 'data:text/html,', # PATCHIN + 'mailto:test@example.com', # PATCHIN + 'file:///etc/passwd', # PATCHIN + ] # PATCHIN + for url in bad_urls: # PATCHIN + self.assertRaises(SuspiciousOperation, # PATCHIN + HttpResponseRedirect, url) # PATCHIN + self.assertRaises(SuspiciousOperation, # PATCHIN + HttpResponsePermanentRedirect, url) # PATCHIN if __name__ == "__main__": import doctest Only in Django-1.1.4/tests/regressiontests: manage.py Only in Django-1.1.4/tests/regressiontests: settings.py