pythonssl

python requests on URL with bad certificate [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE]


I need to get data from a URL that has some certificate problems. It works with curl -k (that skips verification). So I tried with verify=False in python requests but I'm still getting [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE]. Any idea how to bypass this?

I'm using python 3.10.12 and requests 2.32.3 Here goes a code for testing purposes:

import os
import requests

# curl fails
teste = os.system("curl -o capabilities.xml 'https://geoserver.car.gov.br/geoserver/ows?service=WMS&version=1.3.0&request=GetCapabilities'")

# ignoring verification -k works 
teste = os.system("curl -k -o capabilities.xml 'https://geoserver.car.gov.br/geoserver/ows?service=WMS&version=1.3.0&request=GetCapabilities'")

# Trying with python
url = "https://geoserver.car.gov.br/geoserver/ows"
params = {
    'service':'WMS',
    'version':'1.3.0',
    'request':'GetCapabilities'
}

# this fails with certificate error
teste = requests.get(url, params)

# verify = False does not do the trick
teste = requests.get(url, params, verify=False)

Update:

It appears as though the site uses only TLS1.2 for cypher suit and python requests does not like that. Any way to have python use that Cypher?

enter image description here


Solution

  • The problem is not the TLS version, TLS 1.2 is still allowed by default in current Python. The problem is instead that the server only supports weak ciphers which require the obsolete RSA key exchange (i.e. no forward secrecy). To allow this you need to adjust the security level:

    import requests
    import ssl
    from requests.adapters import HTTPAdapter
    
    class CustomSSLAdapter(HTTPAdapter):
        def init_poolmanager(self, *args, **kwargs):
            ssl_context = ssl.create_default_context()
            ssl_context.set_ciphers('DEFAULT@SECLEVEL=0')
            ssl_context.check_hostname = False
    
            kwargs["ssl_context"] = ssl_context
            return super().init_poolmanager(*args, **kwargs)
    
    
    sess = requests.Session()
    sess.mount('https://', CustomSSLAdapter())
    
    url = 'https://geoserver.car.gov.br/geoserver/ows?service=WMS&version=1.3.0&request=GetCapabilities'
    resp = sess.get(url, verify=False)
    print(resp)