14

I am trying to send a POST call using requests library in python to a server. Earlier I was able to successfully send POST calls but recently, the server deprecated TLSv1.0 and now only supports TLSv1.1 and TLSv1.2. Now the same code throws me a "requests.exceptions.SSLError: EOF occurred in violation of protocol (_ssl.c:590)" error.

I found this thread on stackoverflow Python Requests requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocol which says that we need to subclass the HTTPAdapter after which the session object will use TLSv1. I changed my code accordingly and here is my new code

class MyAdapter(HTTPAdapter):
    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=ssl.PROTOCOL_TLSv1
        )

url="https://mywebsite.com/ui/"
headers={"Cookie":"some_value","X-CSRF-Token":"some value","Content-Type":"application/json"}    
payload={"name":"some value","Id":"some value"}    
s = requests.Session()
s.mount('https://', MyAdapter())

r=s.post(url,json=payload,headers=headers)
html=r.text
print html

But even after using this, I get the same error EOF occurred in violation of protocol (_ssl.c:590).

My first question is that, I somewhere read that requests by default uses ssl. I know that my server used TLSv1.0 then, so was my code working because TLSv1.0 has backward compatibility with ssl3.0 ?

My second question is that, the stackoverflow thread that I mentioned above using which I changed my code to subclass HTTPAdapter, said that this will work for TLSv1. But since TLSv1.0 is deprecated in my server, will this code still work?

damon
  • 14,485
  • 14
  • 56
  • 75
Mr. Bing
  • 205
  • 1
  • 3
  • 7

3 Answers3

11

The TLS stack will use the best version available automatically. If it does not work any longer when TLS 1.0 support is disabled at the server it usually means that your local TLS stack simply does not support newer protocol version like TLS 1.2. This is often the case on Mac OS X since it ships with a rotten old version of OpenSSL (0.9.8). In this case no python code will help you to work around the problem, but you need to get a python which uses a newer version of OpenSSL.

To check which openssl version you are using execute the following within python:

import ssl
print(ssl.OPENSSL_VERSION)

To have support for TLS 1.2 you need OpenSSL version 1.0.2 or 1.0.1. If you have only 1.0.0 or 0.9.8 you need to upgrade your python+OpenSSL. See Updating openssl in python 2.7 for more information on how to do this.

TJL
  • 6,330
  • 8
  • 34
  • 36
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • I updated openssl version using the link that you mentioned. But now my program is not running at all. Following is the stack trace: ImportError: dlopen(/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_io.so, 2): Symbol not found: __PyCodecInfo_GetIncrementalDecoder Referenced from: /usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_io.so Expected in: flat namespace in /usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_io.so – Mr. Bing Jul 21 '16 at 12:40
  • 1
    Here is the updated openssl version btw: >>> print ssl.OPENSSL_VERSION OpenSSL 1.0.2h 3 May 2016 – Mr. Bing Jul 21 '16 at 12:41
  • @Mr.Bing: Maybe you did update openssl but you did not recompile python to make properly use of the updated openssl version. Or you are using the wrong version of python and not the one you've just compiled. It's hard to tell but you will find lots of hits for the error messages you see. – Steffen Ullrich Jul 21 '16 at 14:57
3

I was getting random connection errors from very old server (it's rated F by https://www.ssllabs.com) until I wasn't start using this code in my HTTPAdapter:

def init_poolmanager(self, *args, **kwargs):
    ssl_context = ssl.create_default_context()

    # Sets up old and insecure TLSv1.
    ssl_context.options &= ~ssl.OP_NO_TLSv1_3 & ~ssl.OP_NO_TLSv1_2 & ~ssl.OP_NO_TLSv1_1
    ssl_context.minimum_version = ssl.TLSVersion.TLSv1

    # Also you could try to set ciphers manually as it was in my case.
    # On other ciphers their server was reset the connection with:
    # [Errno 104] Connection reset by peer
    # ssl_context.set_ciphers("ECDHE-RSA-AES256-SHA")

    # See urllib3.poolmanager.SSL_KEYWORDS for all available keys.
    kwargs["ssl_context"] = ssl_context

    return super().init_poolmanager(*args, **kwargs)
frost-nzcr4
  • 1,540
  • 11
  • 16
0

Recently there was an update where the urllib dropping TLS 1.0 and 1.1 by default, causing an error in one of the applications I work with. My solution was similiar to the previous one and was as follows:

class SSLAdapter(HTTPAdapter):

    def init_poolmanager(self, *args, **kwargs):
 
        ssl_context = ssl.create_default_context()
        ssl_context.set_ciphers('DEFAULT@SECLEVEL=1')
        ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2

        kwargs["ssl_context"] = ssl_context
        return super().init_poolmanager(*args, **kwargs)
Thales
  • 545
  • 1
  • 6
  • 17