This is part of a larger program I'm working on, but I've got it pinpointed down to the exact problem. When I use Python requests
module in some environments it works but not others and it seems to be related to the cipher suite being used by SSL. When I run the following command in Python, it gives an error or success depending on the OS I'm using. here is the command:
requests.get("https://api-mte.itespp.org/markets/VirtualService/v2/?WSDL")
On Windows 10 and Ubuntu 18.04, it works. But on Windows 11 and Ubuntu 22.04, it does not work and gives the following error:
raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host='api-mte.itespp.org', port=443): Max retries exceeded with url: /markets/VirtualService/v2/?WSDL (Caused by SSLError(SSLError(1, '[SSL: DH_KEY_TOO_SMALL] dh key too small (_ssl.c:997)')))
The part [SSL: DH_KEY_TOO_SMALL] dh key too small
seems to be the relevant part indicating the requests
module thinks the server is using an outdated cipher? When I view the site in Firefox it loads fine.
Am I seeing this correctly or am I off base? This seems to be a relevant question (Python - requests.exceptions.SSLError - dh key too small) but I could not get it to work when I changed requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS
. I know Ubuntu 22 uses OpenSSL v3 while Ubuntu 18 uses OpenSSL v1.1.1 and that seems relevant. Thanks!
EDIT: I believe specifically I'm trying to use the cipher ECDHE-RSA-AES128-GCM-SHA256 or ECDHE-RSA-AES256-GCM-SHA384
So indeed the problem is the server is using an outdated cipher. And the issue is that Windows 11 and Ubuntu 22 will not use that outdated cipher by default. The issue also is that in the version of requests
that I was using (2.31.0), you can no longer change the cipher suite with requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS
as many answers suggest. The answer was found here, a blog post written by I believe one of the authors of the module. It involves making a new adapter from the requests
module so the solution isn't straightforward. This was the code I used to make it work. Obviously you can change custom_ciphers
to whatever is needed.
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
import urllib3
custom_ciphers = [
"ECDHE-RSA-AES256-GCM-SHA384",
# "DHE-RSA-AES256-GCM-SHA384",
# "ECDHE-RSA-AES128-GCM-SHA256",
# "TLS_AES_256_GCM_SHA384",
]
class CustomCipherAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
context = create_urllib3_context(ciphers=":".join(custom_ciphers))
kwargs['ssl_context'] = context
return super(CustomCipherAdapter, self).init_poolmanager(*args, **kwargs)
# Create a session and mount the adapter
session = requests.Session()
session.mount("https://", CustomCipherAdapter())
# Now you can use the session to make requests with the custom cipher suites
response = session.get("https://api-mte.itespp.org/markets/VirtualService/v2/?WSDL")
print(response)
Info about HTTPTransport can be found here.