From 5bedf76da0f76ab2d489972055a5d62066013427 Mon Sep 17 00:00:00 2001 From: Ian Stapleton Cordasco Date: Sun, 3 Mar 2024 07:00:49 -0600 Subject: [PATCH] Use TLS settings in selecting connection pool Previously, if someone made a request with `verify=False` then made a request where they expected verification to be enabled to the same host, they would potentially reuse a connection where TLS had not been verified. This fixes that issue. Upstream-Status: Backport [https://github.com/psf/requests/commit/a58d7f2ffb4d00b46dca2d70a3932a0b37e22fac] CVE: CVE-2024-35195 Signed-off-by: Jiaying Song --- requests/adapters.py | 58 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/requests/adapters.py b/requests/adapters.py index fe22ff4..7ff6998 100644 --- a/requests/adapters.py +++ b/requests/adapters.py @@ -10,6 +10,7 @@ and maintain connections. import os.path import socket +import typing from urllib3.poolmanager import PoolManager, proxy_from_url from urllib3.response import HTTPResponse @@ -47,12 +48,38 @@ except ImportError: def SOCKSProxyManager(*args, **kwargs): raise InvalidSchema("Missing dependencies for SOCKS support.") +if typing.TYPE_CHECKING: + from .models import PreparedRequest + + DEFAULT_POOLBLOCK = False DEFAULT_POOLSIZE = 10 DEFAULT_RETRIES = 0 DEFAULT_POOL_TIMEOUT = None +def _urllib3_request_context( + request: "PreparedRequest", verify: "bool | str | None" +) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])": + host_params = {} + pool_kwargs = {} + parsed_request_url = urlparse(request.url) + scheme = parsed_request_url.scheme.lower() + port = parsed_request_url.port + cert_reqs = "CERT_REQUIRED" + if verify is False: + cert_reqs = "CERT_NONE" + if isinstance(verify, str): + pool_kwargs["ca_certs"] = verify + pool_kwargs["cert_reqs"] = cert_reqs + host_params = { + "scheme": scheme, + "host": parsed_request_url.hostname, + "port": port, + } + return host_params, pool_kwargs + + class BaseAdapter(object): """The Base Transport Adapter""" @@ -290,6 +317,35 @@ class HTTPAdapter(BaseAdapter): return response + def _get_connection(self, request, verify, proxies=None): + # Replace the existing get_connection without breaking things and + # ensure that TLS settings are considered when we interact with + # urllib3 HTTP Pools + proxy = select_proxy(request.url, proxies) + try: + host_params, pool_kwargs = _urllib3_request_context(request, verify) + except ValueError as e: + raise InvalidURL(e, request=request) + if proxy: + proxy = prepend_scheme_if_needed(proxy, "http") + proxy_url = parse_url(proxy) + if not proxy_url.host: + raise InvalidProxyURL( + "Please check proxy URL. It is malformed " + "and could be missing the host." + ) + proxy_manager = self.proxy_manager_for(proxy) + conn = proxy_manager.connection_from_host( + **host_params, pool_kwargs=pool_kwargs + ) + else: + # Only scheme should be lower case + conn = self.poolmanager.connection_from_host( + **host_params, pool_kwargs=pool_kwargs + ) + + return conn + def get_connection(self, url, proxies=None): """Returns a urllib3 connection for the given URL. This should not be called from user code, and is only exposed for use when subclassing the @@ -410,7 +466,7 @@ class HTTPAdapter(BaseAdapter): """ try: - conn = self.get_connection(request.url, proxies) + conn = self._get_connection(request, verify, proxies) except LocationValueError as e: raise InvalidURL(e, request=request) -- 2.25.1