+74
-0
lines changedFilter options
+74
-0
lines changed Original file line number Diff line number Diff line change
@@ -783,6 +783,10 @@ HTTPRedirectHandler Objects
783
783
is the case, :exc:`HTTPError` is raised. See :rfc:`2616` for details of the
784
784
precise meanings of the various redirection codes.
785
785
786
+
An :class:`HTTPError` exception raised as a security consideration if the
787
+
HTTPRedirectHandler is presented with a redirected url which is not an HTTP,
788
+
HTTPS or FTP url.
789
+
786
790
787
791
.. method:: HTTPRedirectHandler.redirect_request(req, fp, code, msg, hdrs, newurl)
788
792
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
2
2
3
3
import urllib.parse
4
4
import urllib.request
5
+
import urllib.error
5
6
import http.client
6
7
import email.message
7
8
import io
@@ -183,6 +184,21 @@ def test_read_bogus(self):
183
184
finally:
184
185
self.unfakehttp()
185
186
187
+
def test_invalid_redirect(self):
188
+
# urlopen() should raise IOError for many error codes.
189
+
self.fakehttp(b'''HTTP/1.1 302 Found
190
+
Date: Wed, 02 Jan 2008 03:03:54 GMT
191
+
Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
192
+
Location: file://guidocomputer.athome.com:/python/license
193
+
Connection: close
194
+
Content-Type: text/html; charset=iso-8859-1
195
+
''')
196
+
try:
197
+
self.assertRaises(urllib.error.HTTPError, urlopen,
198
+
"http://python.org/")
199
+
finally:
200
+
self.unfakehttp()
201
+
186
202
def test_empty_socket(self):
187
203
# urlopen() raises IOError if the underlying socket does not send any
188
204
# data. (#1680230)
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
9
9
# The proxy bypass method imported below has logic specific to the OSX
10
10
# proxy config data structure but is testable on all platforms.
11
11
from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
12
+
import urllib.error
12
13
13
14
# XXX
14
15
# Request
@@ -985,6 +986,29 @@ def redirect(h, req, url=to_url):
985
986
self.assertEqual(count,
986
987
urllib.request.HTTPRedirectHandler.max_redirections)
987
988
989
+
990
+
def test_invalid_redirect(self):
991
+
from_url = "http://example.com/a.html"
992
+
valid_schemes = ['http','https','ftp']
993
+
invalid_schemes = ['file','imap','ldap']
994
+
schemeless_url = "example.com/b.html"
995
+
h = urllib.request.HTTPRedirectHandler()
996
+
o = h.parent = MockOpener()
997
+
req = Request(from_url)
998
+
req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
999
+
1000
+
for scheme in invalid_schemes:
1001
+
invalid_url = scheme + '://' + schemeless_url
1002
+
self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1003
+
req, MockFile(), 302, "Security Loophole",
1004
+
MockHeaders({"location": invalid_url}))
1005
+
1006
+
for scheme in valid_schemes:
1007
+
valid_url = scheme + '://' + schemeless_url
1008
+
h.http_error_302(req, MockFile(), 302, "That's fine",
1009
+
MockHeaders({"location": valid_url}))
1010
+
self.assertEqual(o.req.get_full_url(), valid_url)
1011
+
988
1012
def test_cookie_redirect(self):
989
1013
# cookies shouldn't leak into redirected requests
990
1014
from http.cookiejar import CookieJar
Original file line number Diff line number Diff line change
@@ -528,6 +528,17 @@ def http_error_302(self, req, fp, code, msg, headers):
528
528
529
529
# fix a possible malformed URL
530
530
urlparts = urlparse(newurl)
531
+
532
+
# For security reasons we don't allow redirection to anything other
533
+
# than http, https or ftp.
534
+
535
+
if not urlparts.scheme in ('http', 'https', 'ftp'):
536
+
raise HTTPError(newurl, code,
537
+
msg +
538
+
" - Redirection to url '%s' is not allowed" %
539
+
newurl,
540
+
headers, fp)
541
+
531
542
if not urlparts.path:
532
543
urlparts = list(urlparts)
533
544
urlparts[2] = "/"
@@ -1864,8 +1875,24 @@ def redirect_internal(self, url, fp, errcode, errmsg, headers, data):
1864
1875
return
1865
1876
void = fp.read()
1866
1877
fp.close()
1878
+
1867
1879
# In case the server sent a relative URL, join with original:
1868
1880
newurl = urljoin(self.type + ":" + url, newurl)
1881
+
1882
+
urlparts = urlparse(newurl)
1883
+
1884
+
# For security reasons, we don't allow redirection to anything other
1885
+
# than http, https and ftp.
1886
+
1887
+
# We are using newer HTTPError with older redirect_internal method
1888
+
# This older method will get deprecated in 3.3
1889
+
1890
+
if not urlparts.scheme in ('http', 'https', 'ftp'):
1891
+
raise HTTPError(newurl, errcode,
1892
+
errmsg +
1893
+
" Redirection to url '%s' is not allowed." % newurl,
1894
+
headers, fp)
1895
+
1869
1896
return self.open(newurl)
1870
1897
1871
1898
def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
Original file line number Diff line number Diff line change
@@ -44,6 +44,9 @@ Core and Builtins
44
44
Library
45
45
-------
46
46
47
+
- Issue #11662: Make urllib and urllib2 ignore redirections if the
48
+
scheme is not HTTP, HTTPS or FTP (CVE-2011-1521).
49
+
47
50
- Issue #5537: Fix time2isoz() and time2netscape() functions of
48
51
httplib.cookiejar for expiration year greater than 2038 on 32-bit systems.
49
52
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4