You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
3.6 KiB
92 lines
3.6 KiB
From 20f7d039446f71c40ea240c0a9f6e2465659ec68 Mon Sep 17 00:00:00 2001 |
|
From: Lumir Balhar <lbalhar@redhat.com> |
|
Date: Mon, 13 Jan 2020 09:31:42 +0100 |
|
Subject: [PATCH 1/2] CVE-2018-20060 |
|
|
|
--- |
|
poolmanager.py | 11 ++++++++++- |
|
util/retry.py | 11 ++++++++++- |
|
2 files changed, 20 insertions(+), 2 deletions(-) |
|
|
|
diff --git a/poolmanager.py b/poolmanager.py |
|
index 1023dcb..b87f315 100644 |
|
--- a/poolmanager.py |
|
+++ b/poolmanager.py |
|
@@ -156,8 +156,9 @@ class PoolManager(RequestMethods): |
|
|
|
kw['assert_same_host'] = False |
|
kw['redirect'] = False |
|
+ |
|
if 'headers' not in kw: |
|
- kw['headers'] = self.headers |
|
+ kw['headers'] = self.headers.copy() |
|
|
|
if self.proxy is not None and u.scheme == "http": |
|
response = conn.urlopen(method, url, **kw) |
|
@@ -179,6 +180,14 @@ class PoolManager(RequestMethods): |
|
if not isinstance(retries, Retry): |
|
retries = Retry.from_int(retries, redirect=redirect) |
|
|
|
+ # Strip headers marked as unsafe to forward to the redirected location. |
|
+ # Check remove_headers_on_redirect to avoid a potential network call within |
|
+ # conn.is_same_host() which may use socket.gethostbyname() in the future. |
|
+ if (retries.remove_headers_on_redirect |
|
+ and not conn.is_same_host(redirect_location)): |
|
+ for header in retries.remove_headers_on_redirect: |
|
+ kw['headers'].pop(header, None) |
|
+ |
|
try: |
|
retries = retries.increment(method, url, response=response, _pool=conn) |
|
except MaxRetryError: |
|
diff --git a/util/retry.py b/util/retry.py |
|
index 2d3aa20..d6bd74e 100644 |
|
--- a/util/retry.py |
|
+++ b/util/retry.py |
|
@@ -103,6 +103,11 @@ class Retry(object): |
|
exhausted, to raise a MaxRetryError, or to return a response with a |
|
response code in the 3xx range. |
|
|
|
+ :param iterable remove_headers_on_redirect: |
|
+ Sequence of headers to remove from the request when a response |
|
+ indicating a redirect is returned before firing off the redirected |
|
+ request |
|
+ |
|
:param bool raise_on_status: Similar meaning to ``raise_on_redirect``: |
|
whether we should raise an exception, or return a response, |
|
if status falls in ``status_forcelist`` range and retries have |
|
@@ -112,13 +117,15 @@ class Retry(object): |
|
DEFAULT_METHOD_WHITELIST = frozenset([ |
|
'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) |
|
|
|
+ DEFAULT_REDIRECT_HEADERS_BLACKLIST = frozenset(['Authorization']) |
|
+ |
|
#: Maximum backoff time. |
|
BACKOFF_MAX = 120 |
|
|
|
def __init__(self, total=10, connect=None, read=None, redirect=None, |
|
method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, |
|
backoff_factor=0, raise_on_redirect=True, raise_on_status=True, |
|
- _observed_errors=0): |
|
+ _observed_errors=0, remove_headers_on_redirect=DEFAULT_REDIRECT_HEADERS_BLACKLIST): |
|
|
|
self.total = total |
|
self.connect = connect |
|
@@ -135,6 +142,7 @@ class Retry(object): |
|
self.raise_on_redirect = raise_on_redirect |
|
self.raise_on_status = raise_on_status |
|
self._observed_errors = _observed_errors # TODO: use .history instead? |
|
+ self.remove_headers_on_redirect = remove_headers_on_redirect |
|
|
|
def new(self, **kw): |
|
params = dict( |
|
@@ -146,6 +154,7 @@ class Retry(object): |
|
raise_on_redirect=self.raise_on_redirect, |
|
raise_on_status=self.raise_on_status, |
|
_observed_errors=self._observed_errors, |
|
+ remove_headers_on_redirect=self.remove_headers_on_redirect, |
|
) |
|
params.update(kw) |
|
return type(self)(**params) |
|
-- |
|
2.24.1 |
|
|
|
|