Python - requests.exceptions.SSLError - dh key too small
Disabling warnings or certificate validation will not help. The underlying problem is a weak DH key used by the server which can be misused in the Logjam Attack.
To work around this you need to chose a cipher which does not make any use of Diffie Hellman Key Exchange and thus is not affected by the weak DH key. And this cipher must be supported by the server. It is unknown what the server supports but you might try with the cipher AES128-SHA
or a cipher set of HIGH:!DH:!aNULL
Using requests with your own cipher set is tricky. See Why does Python requests ignore the verify parameter? for an example.
Python dh key too small, which side is faulty?
Question: Is the issue on my end, or on the destination's server end?The server is offering a weak DH key, the client (your script) wants a stronger key. The problem should usually be fixed at the server side. And note that your call of
load_dh_params
makes no sense since setting the DH key is only relevant for the server side.Is there something I can do to avoid this issue?Don't use DH ciphers in the first place. All modern clients support ECDHE ciphers which don't have this problem. DH is very slow anyway.
Usually the client would also choose a ECDHE cipher if offered and this error will not happen. While it might be that the TLS stack at the client is too old and prefers DH, such an old stack would usually not complain about a weak DH. It is thus more likely that the servers SSL stack is too old so that it does not offer the more modern ciphers the clients wants by default.
To make sure that no DH ciphers are offered by the client and thus ECDHE or RSA key exchange is used set the ciphers accordingly:
ssl_context.set_ciphers('DEFAULT:!DH')
Note though that RSA key exchange is considered obsolete too since it does not provide any forward secrecy. You might therefore try if the server can do without DH and without kRSA by using a cipher string of DEFAULT:!DH:!kRSA
. How to change/tweak Python 3.10 default SSL settings for requests - sslv3 alert handshake failure
@PatrickMevzek 's comment led me to other queries and this question.
Which showed me how to change the used ciphers AND security level. The following snippet from @bgoeman worked for my environment:
import urllib3
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL:@SECLEVEL=1'
Obviously, in general THIS SHOULD NOT BE USED. This will allow for man-in-the-middle attacks and other nasty things. Be careful and mindful when changing these settings. Python request SSL error only inside docker container
couple of related issues:
- Docker python requests results in DH KEY TOO SMALL error
- Python referencing old SSL version
in the python3 container:
# openssl version
OpenSSL 1.1.1 11 Sep 2019
# python -c "import ssl; print(ssl.OPENSSL_VERSION)"
OpenSSL 1.1.1 11 Sep 2018
I wasn't sure how to install another OpenSSL version on the python image, so I just switched to ubuntu:18.04 which has the right version. Docker python requests results in DH KEY TOO SMALL error
I've managed to fix the issue. The problem was caused by openssl versions. Both my windows 10 pc and ubuntu 18.04 vm run an older version that had no problem connecting to the website. The python docker images contain a newer version of openssl that refused to connect.
Related Topics
Typeerror: Got Multiple Values for Argument
How to Set Opacity of Background Colour of Graph with Matplotlib
How Dangerous Is Setting Self._Class_ to Something Else
What Is the Official "Preferred" Way to Install Pip and Virtualenv Systemwide
First Python List Index Greater Than X
Is There a Function to Determine Which Quarter of the Year a Date Is In
In Python, Why Is List[] Automatically Global
Change Tick Frequency on X (Time, Not Number) Frequency in Matplotlib
How to Find the Maximum Value in a List of Tuples
When Should an Attribute Be Private and Made a Read-Only Property
How to Check Task Status in Celery
Getting Data from Ctypes Array into Numpy
Using "And" and "Or" Operator with Python Strings
How Does Sklearn.Svm.Svc's Function Predict_Proba() Work Internally
How to Read a File Line-By-Line in Python
Display Realtime Output of a Subprocess in a Tkinter Widget