I am running a Python code where I have to get some data from HTTPSConnectionPool(host='ssd.jpl.nasa.gov', port=443). But each time I try to run the code I get the following error. I am on MAC OS 12.1
raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host='ssd.jpl.nasa.gov', port=443): Max retries exceeded with url: /api/horizons.api?format=text&EPHEM_TYPE=OBSERVER&QUANTITIES_[...]_ (Caused by SSLError(SSLError(1, '[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled (_ssl.c:997)'))) I really don't know how to bypass this issue.
12 Answers
WARNING: When enabling Legacy Unsafe Renegotiation, SSL connections will be vulnerable to the Man-in-the-Middle prefix attack as described in CVE-2009-3555.
Beware that editing your system's openssl.conf is not recommended, because you might lose your changes once openssl is updated.
Create a custom openssl.cnf file in any directory with these contents:
openssl_conf = openssl_init [openssl_init] ssl_conf = ssl_sect [ssl_sect] system_default = system_default_sect [system_default_sect] Options = UnsafeLegacyRenegotiation Before running your program, make sure your OPENSSL_CONF environment variable is set to your custom openssl.cnf full path when running the scraper like so:
OPENSSL_CONF=/path/to/custom/openssl.cnf python your_scraper.py or like so:
export OPENSSL_CONF=/path/to/custom/openssl.cnf python your_scraper.py or, if you are using pipenv or systemd or docker, place this into your .env file
OPENSSL_CONF=/path/to/custom/openssl.cnf 3Complete code snippets for Harry Mallon's answer:
Define a method for reuse:
import requests import urllib3 import ssl class CustomHttpAdapter (requests.adapters.HTTPAdapter): # "Transport adapter" that allows us to use custom ssl_context. def __init__(self, ssl_context=None, **kwargs): self.ssl_context = ssl_context super().__init__(**kwargs) def init_poolmanager(self, connections, maxsize, block=False): self.poolmanager = urllib3.poolmanager.PoolManager( num_pools=connections, maxsize=maxsize, block=block, ssl_context=self.ssl_context) def get_legacy_session(): ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) ctx.options |= 0x4 # OP_LEGACY_SERVER_CONNECT session = requests.session() session.mount(' CustomHttpAdapter(ctx)) return session Then use it in place of the requests call:
get_legacy_session().get("some-url") 2I hit the same error on Linux (it happens when the server doesn't support "RFC 5746 secure renegotiation" and the client is using OpenSSL 3, which enforces that standard by default).
Here is a solution (you may have to adjust it slightly).
- Import
sslandurllib3in your Python code - Create a custom HttpAdapter which uses a custom
sslContext
class CustomHttpAdapter (requests.adapters.HTTPAdapter): '''Transport adapter" that allows us to use custom ssl_context.''' def __init__(self, ssl_context=None, **kwargs): self.ssl_context = ssl_context super().__init__(**kwargs) def init_poolmanager(self, connections, maxsize, block=False): self.poolmanager = urllib3.poolmanager.PoolManager( num_pools=connections, maxsize=maxsize, block=block, ssl_context=self.ssl_context) - Set up an
sslcontext which enablesOP_LEGACY_SERVER_CONNECT, and use it with your custom adapter.
ssl.OP_LEGACY_SERVER_CONNECT is not available in Python yet (). However it turns out that in OpenSSL its value is 0x4 in the bitfield. So we can do the following.
ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) ctx.options |= 0x4 session.mount(' CustomHttpAdapter(ctx)) 9This error comes up when using OpenSSL 3 to connect to a server which does not support it. The solution is to downgrade the cryptography package in python:
run pip install cryptography==36.0.2 in the used enviroment.
EDIT: Refer to Hally Mallon and ahmkara's answer for a fix without downgrading cryptography
4This doesn't really answer the issue, but a coworker switched from Node 18 to 16 and stopped getting this error.
If you want to use urlopen, this snippet worked for me.
import ssl import urllib.request url = ' # Set up SSL context to allow legacy TLS versions ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) ctx.options |= 0x4 # OP_LEGACY_SERVER_CONNECT # Use urllib to open the URL and read the content response = urllib.request.urlopen(url, context=ctx) To fix the same problem in ruby you can do below:
# Set OP_LEGACY_SERVER_CONNECT option OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_LEGACY_SERVER_CONNECT # Make a request uri = URI(') res = Net::HTTP.post(uri, {}.to_json) # Unset OP_LEGACY_SERVER_CONNECT option OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] &= ~OpenSSL::SSL::OP_LEGACY_SERVER_CONNECT If you are using conda, usually conda installs a new openssl executable with each environment. One easy fix is to downgrade your openssl to 1.0 by running the following with your environment.
conda install -n conda-env-name openssl=1 Or find where the openssl config is for your specific conda environment and follow Jack Lee's answer.
You'll have to closely monitor the SSL versions from this website to ensure you specify the correct channel.
There are quite a few answers on this thread. None of them quite met my needs, so I figured I'd contribute my own solution as well. Hopefully others find it valuable.
My Setup
I am running Python 3.10 on Ubuntu 22.04.2. I am using aiohttp to make HTTP requests asynchronously.
I am making an HTTP request to a piece of hardware on my internal LAN, and I cannot update this hardware to simply stop using the insecure SSL renegotiation.
My Approach
I created a custom SSL context, and then passed in the SSL OP flag 'SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION'. I got this flag from here: List of SSL OP Flags
custom_ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) custom_ssl_context.options |= 0x00040000 # OP flag SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION connector = aiohttp.TCPConnector(ssl=custom_ssl_context) async with aiohttp.ClientSession(connector=connector) as session: async with session.get(url) as response: return await response.text() If you also need to disable SSL verification (in the case of development testing for example), you can add the following two lines to your custom_ssl_context:
custom_ssl_context.check_hostname = False custom_ssl_context.verify_mode = ssl.CERT_NONE Now I resolve issue it - [SSL error unsafe legacy renegotiation disabled] or (Caused by SSLError(SSLError(1, '[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled (_ssl.c:1007)'))) reference link below : but it's not used just try to understand the problem
(SSL error unsafe legacy renegotiation disabled) use below code :
import urllib.request import ssl # Create a secure SSL context ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS) # Use the appropriate protocol url = "" # Replace with your URL response = urllib.request.urlopen(url, context=ssl_context) # Read and process the response data = response.read().decode("utf-8") For me, I switch the url from https into http. Please be aware that HTTP does not provide the same level of security as HTTPS
1For me, it worked when I downgraded python to v3.10.8.
(If you are facing the issue in docker container, read below)
In my docker image, I was using alpine-10 which was using v3.10.9. Since I couldn't get alpine with v3.10.8, I used 3.10.8-slim-bullseye.
1