107 lines
4.3 KiB
Diff
107 lines
4.3 KiB
Diff
|
|
||
|
# HG changeset patch
|
||
|
# User Guido van Rossum <guido@python.org>
|
||
|
# Date 1301428435 25200
|
||
|
# Node ID b2934d98dac1f7b13cc6cc280f06d1aec3f6e80d
|
||
|
# Parent 1a5aab273332a7a379e35ed6f88400a110b5de0c# Parent 9eeda8e3a13f107a698f10b0a45ffc2c6bd710fb
|
||
|
Merge issue 11662 from 2.6.
|
||
|
|
||
|
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py
|
||
|
--- a/Lib/test/test_urllib.py
|
||
|
+++ b/Lib/test/test_urllib.py
|
||
|
@@ -161,6 +161,20 @@ Content-Type: text/html; charset=iso-885
|
||
|
finally:
|
||
|
self.unfakehttp()
|
||
|
|
||
|
+ def test_invalid_redirect(self):
|
||
|
+ # urlopen() should raise IOError for many error codes.
|
||
|
+ self.fakehttp("""HTTP/1.1 302 Found
|
||
|
+Date: Wed, 02 Jan 2008 03:03:54 GMT
|
||
|
+Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
|
||
|
+Location: file:README
|
||
|
+Connection: close
|
||
|
+Content-Type: text/html; charset=iso-8859-1
|
||
|
+""")
|
||
|
+ try:
|
||
|
+ self.assertRaises(IOError, urllib.urlopen, "http://python.org/")
|
||
|
+ finally:
|
||
|
+ self.unfakehttp()
|
||
|
+
|
||
|
def test_empty_socket(self):
|
||
|
# urlopen() raises IOError if the underlying socket does not send any
|
||
|
# data. (#1680230)
|
||
|
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
|
||
|
--- a/Lib/test/test_urllib2.py
|
||
|
+++ b/Lib/test/test_urllib2.py
|
||
|
@@ -969,6 +969,27 @@ class HandlerTests(unittest.TestCase):
|
||
|
self.assertEqual(count,
|
||
|
urllib2.HTTPRedirectHandler.max_redirections)
|
||
|
|
||
|
+ def test_invalid_redirect(self):
|
||
|
+ from_url = "http://example.com/a.html"
|
||
|
+ valid_schemes = ['http', 'https', 'ftp']
|
||
|
+ invalid_schemes = ['file', 'imap', 'ldap']
|
||
|
+ schemeless_url = "example.com/b.html"
|
||
|
+ h = urllib2.HTTPRedirectHandler()
|
||
|
+ o = h.parent = MockOpener()
|
||
|
+ req = Request(from_url)
|
||
|
+
|
||
|
+ for scheme in invalid_schemes:
|
||
|
+ invalid_url = scheme + '://' + schemeless_url
|
||
|
+ self.assertRaises(urllib2.HTTPError, h.http_error_302,
|
||
|
+ req, MockFile(), 302, "Security Loophole",
|
||
|
+ MockHeaders({"location": invalid_url}))
|
||
|
+
|
||
|
+ for scheme in valid_schemes:
|
||
|
+ valid_url = scheme + '://' + schemeless_url
|
||
|
+ h.http_error_302(req, MockFile(), 302, "That's fine",
|
||
|
+ MockHeaders({"location": valid_url}))
|
||
|
+ self.assertEqual(o.req.get_full_url(), valid_url)
|
||
|
+
|
||
|
def test_cookie_redirect(self):
|
||
|
# cookies shouldn't leak into redirected requests
|
||
|
from cookielib import CookieJar
|
||
|
diff --git a/Lib/urllib.py b/Lib/urllib.py
|
||
|
--- a/Lib/urllib.py
|
||
|
+++ b/Lib/urllib.py
|
||
|
@@ -644,6 +644,18 @@ class FancyURLopener(URLopener):
|
||
|
fp.close()
|
||
|
# In case the server sent a relative URL, join with original:
|
||
|
newurl = basejoin(self.type + ":" + url, newurl)
|
||
|
+
|
||
|
+ # For security reasons we do not allow redirects to protocols
|
||
|
+ # other than HTTP, HTTPS or FTP.
|
||
|
+ newurl_lower = newurl.lower()
|
||
|
+ if not (newurl_lower.startswith('http://') or
|
||
|
+ newurl_lower.startswith('https://') or
|
||
|
+ newurl_lower.startswith('ftp://')):
|
||
|
+ raise IOError('redirect error', errcode,
|
||
|
+ errmsg + " - Redirection to url '%s' is not allowed" %
|
||
|
+ newurl,
|
||
|
+ headers)
|
||
|
+
|
||
|
return self.open(newurl)
|
||
|
|
||
|
def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
|
||
|
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
|
||
|
--- a/Lib/urllib2.py
|
||
|
+++ b/Lib/urllib2.py
|
||
|
@@ -578,6 +578,17 @@ class HTTPRedirectHandler(BaseHandler):
|
||
|
|
||
|
newurl = urlparse.urljoin(req.get_full_url(), newurl)
|
||
|
|
||
|
+ # For security reasons we do not allow redirects to protocols
|
||
|
+ # other than HTTP, HTTPS or FTP.
|
||
|
+ newurl_lower = newurl.lower()
|
||
|
+ if not (newurl_lower.startswith('http://') or
|
||
|
+ newurl_lower.startswith('https://') or
|
||
|
+ newurl_lower.startswith('ftp://')):
|
||
|
+ raise HTTPError(newurl, code,
|
||
|
+ msg + " - Redirection to url '%s' is not allowed" %
|
||
|
+ newurl,
|
||
|
+ headers, fp)
|
||
|
+
|
||
|
# XXX Probably want to forget about the state of the current
|
||
|
# request, although that might interact poorly with other
|
||
|
# handlers that also use handler-specific request attributes
|