|
11 | 11 | from io import BytesIO |
12 | 12 | from pprint import pformat |
13 | 13 | try: |
14 | | - from urllib.parse import quote, parse_qsl, urlencode, urljoin |
| 14 | + from urllib.parse import quote, parse_qsl, urlencode, urljoin, urlparse |
15 | 15 | except ImportError: # Python 2 |
16 | 16 | from urllib import quote, urlencode |
17 | | - from urlparse import parse_qsl, urljoin |
| 17 | + from urlparse import parse_qsl, urljoin, urlparse |
18 | 18 |
|
19 | 19 | from django.utils.six.moves import http_cookies |
20 | 20 | # Some versions of Python 2.7 and later won't need this encoding bug fix: |
@@ -80,7 +80,7 @@ def _BaseCookie__set(self, key, real_value, coded_value): |
80 | 80 |
|
81 | 81 | from django.conf import settings |
82 | 82 | from django.core import signing |
83 | | -from django.core.exceptions import ImproperlyConfigured |
| 83 | +from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation |
84 | 84 | from django.core.files import uploadhandler |
85 | 85 | from django.http.multipartparser import MultiPartParser |
86 | 86 | from django.http.utils import * |
@@ -689,20 +689,22 @@ def tell(self): |
689 | 689 | raise Exception("This %s instance cannot tell its position" % self.__class__) |
690 | 690 | return sum([len(chunk) for chunk in self]) |
691 | 691 |
|
692 | | -class HttpResponseRedirect(HttpResponse): |
693 | | - status_code = 302 |
| 692 | +class HttpResponseRedirectBase(HttpResponse): |
| 693 | + allowed_schemes = ['http', 'https', 'ftp'] |
694 | 694 |
|
695 | 695 | def __init__(self, redirect_to): |
696 | | - super(HttpResponseRedirect, self).__init__() |
| 696 | + parsed = urlparse(redirect_to) |
| 697 | + if parsed.scheme and parsed.scheme not in self.allowed_schemes: |
| 698 | + raise SuspiciousOperation("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) |
| 699 | + super(HttpResponseRedirectBase, self).__init__() |
697 | 700 | self['Location'] = iri_to_uri(redirect_to) |
| 701 | + |
| 702 | +class HttpResponseRedirect(HttpResponseRedirectBase): |
| 703 | + status_code = 302 |
698 | 704 |
|
699 | | -class HttpResponsePermanentRedirect(HttpResponse): |
| 705 | +class HttpResponsePermanentRedirect(HttpResponseRedirectBase): |
700 | 706 | status_code = 301 |
701 | 707 |
|
702 | | - def __init__(self, redirect_to): |
703 | | - super(HttpResponsePermanentRedirect, self).__init__() |
704 | | - self['Location'] = iri_to_uri(redirect_to) |
705 | | - |
706 | 708 | class HttpResponseNotModified(HttpResponse): |
707 | 709 | status_code = 304 |
708 | 710 |
|
|
0 commit comments