0

I'm having a very particular problem. In particular, I'd like to retrieve the content of the following website: https://www.mycardtamoil.it/

As I understood, this website has some issues with the SSL certificate. If you open it in Chrome, you have no issue, but if you try to retrieve the content via cURL (curl https://www.mycardtamoil.it/) you receive an error on ssl that can bypass using the option -k

When I move to Python3, I'm not able to bypass this issue; the code I've tested is:

import requests
response = requests.get('https://www.mycardtamoil.it/', verify=False)

but I get the following expection:

--------------------------------------------------------------------------- SysCallError Traceback (most recent call last) C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py in wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname) 440 try: --> 441 cnx.do_handshake() 442 except OpenSSL.SSL.WantReadError:

C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py in do_handshake(self) 1906 result = _lib.SSL_do_handshake(self._ssl) -> 1907 self._raise_ssl_error(self._ssl, result) 1908

C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py in _raise_ssl_error(self, ssl, result) 1631 raise SysCallError(errno, errorcode.get(errno)) -> 1632 raise SysCallError(-1, "Unexpected EOF") 1633 else:

SysCallError: (-1, 'Unexpected EOF')

During handling of the above exception, another exception occurred:

SSLError Traceback (most recent call last) C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py in urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw) 600 body=body, headers=headers, --> 601 chunked=chunked) 602

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py in _make_request(self, conn, method, url, timeout, chunked, **httplib_request_kw) 345 try: --> 346 self._validate_conn(conn) 347 except (SocketTimeout, BaseSSLError) as e:

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py in _validate_conn(self, conn) 849 if not getattr(conn, 'sock', None): # AppEngine might not have .sock --> 850 conn.connect() 851

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connection.py in connect(self) 325 server_hostname=hostname, --> 326 ssl_context=context) 327

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\ssl_.py in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir) 328 if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI --> 329 return context.wrap_socket(sock, server_hostname=server_hostname) 330

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py in wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname) 447 except OpenSSL.SSL.Error as e: --> 448 raise ssl.SSLError('bad handshake: %r' % e) 449 break

SSLError: ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)

During handling of the above exception, another exception occurred:

MaxRetryError Traceback (most recent call last) C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py in send(self, request, stream, timeout, verify, cert, proxies) 439 retries=self.max_retries, --> 440 timeout=timeout 441 )

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py in urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw) 638 retries = retries.increment(method, url, error=e, _pool=self, --> 639 _stacktrace=sys.exc_info()[2]) 640 retries.sleep()

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\retry.py in increment(self, method, url, response, error, _pool, _stacktrace) 387 if new_retry.is_exhausted(): --> 388 raise MaxRetryError(_pool, url, error or ResponseError(cause)) 389

MaxRetryError: HTTPSConnectionPool(host='www.mycardtamoil.it', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: SysCallError(-1, 'Unexpected EOF')",),))

During handling of the above exception, another exception occurred:

SSLError Traceback (most recent call last) in () 1 import requests ----> 2 response = requests.get('https://www.mycardtamoil.it/', verify=False)

C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py in get(url, params, **kwargs) 70 71 kwargs.setdefault('allow_redirects', True) ---> 72 return request('get', url, params=params, **kwargs) 73 74

C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py in request(method, url, **kwargs) 56 # cases, and look like a memory leak in others. 57 with sessions.Session() as session: ---> 58 return session.request(method=method, url=url, **kwargs) 59 60

C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json) 506 } 507 send_kwargs.update(settings) --> 508 resp = self.send(prep, **send_kwargs) 509 510 return resp

C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py in send(self, request, **kwargs) 616 617 # Send the request --> 618 r = adapter.send(request, **kwargs) 619 620 # Total elapsed time of the request (approximately)

C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py in send(self, request, stream, timeout, verify, cert, proxies) 504 if isinstance(e.reason, _SSLError): 505 # This branch is for urllib3 v1.22 and later. --> 506 raise SSLError(e, request=request) 507 508 raise ConnectionError(e, request=request)

SSLError: HTTPSConnectionPool(host='www.mycardtamoil.it', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: SysCallError(-1, 'Unexpected EOF')",),))

Can someone help me to understand how I can fix it using requests module?

Thanks in advance, Salvo

nos_86
  • 13
  • 1
  • 2
  • 11

1 Answers1

6

According to SSLLabs the server has a terrible setup. Notably it only supports TLS 1.0 and less (even the more or less broken SSLv3 and the absolutely broken SSLv2) and it also only supports ciphers which are considered weak or really insecure.

While clients usually support TLS 1.0 (still considered sufficiently secure despite known problems) they usually don't support weak and insecure ciphers - at least by default but sometimes they are not even compiled in any longer. Probably the less insecure cipher supported by the server is TLS_RSA_WITH_3DES_EDE_CBC_SHA (called DES-CBC3-SHA within OpenSSL).

Assuming that this cipher is still available in the version of OpenSSL used by your Python you could hack requests into enable this cipher. Based on this question this could be done like this:

import requests
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DES-CBC3-SHA'
requests.get('https://www.mycardtamoil.it/')

While it now no longer gets a Unexpected EOF it gets another error: certificate verify failed. This is because the servers setup is not only broken regarding protocol versions and ciphers but also the certificate is not properly configured. The SSLLabs report shows among all the other problems also

This server's certificate chain is incomplete.

Adding verify=False like you did "fixes" the problem by adding even more insecurity, i.e. it skips the validation of the certificate. See here for how such situations can be properly fixed. Although, it is not clear if properly checking the certificate would actually significantly improve the security in this situation where you have to deal with a severely broken and insecure system. I recommend to not sent any sensitive data to this system, no matter if HTTPS is used or not.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Thank you, for your very clear explanation. Now it works. As you highlighted, this server configuration is very unsecure. I'll avoid to send any sensitive data as you suggested – nos_86 Nov 06 '18 at 09:17
  • @Steffen Ullrich I wrote 'requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DES-CBC3-SHA' ' this code in mine. But I get error **no chiper match**. How can I make default again? – Ahmet Yılmaz Jan 16 '20 at 16:25
  • @AhmetYılmaz: I have no real idea of what you are trying to do. Explicitly overriding the default ciphers should only be done if needed since the relevant cipher is not in there. If you want to use the default ciphers from Python simple don't override the default ciphers. – Steffen Ullrich Jan 16 '20 at 17:37
  • @AhmetYılmaz: I have no real idea of what you are trying to do. Explicitly overriding the default ciphers should only be done if needed since the relevant cipher is not in there. If you want to use the default ciphers from Python simple don't override the default ciphers. – Steffen Ullrich Jan 16 '20 at 17:37
  • @SteffenUllrich I solved it with this code: 'requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL' ' – Ahmet Yılmaz Jan 17 '20 at 06:09
  • 1
    @AhmetYılmaz: This is not "solved". This is worked around with a seemingly working code which has the problem of allowing also terrible insecure ciphers. Note that when dealing with security it does not mean it is secure if it just works. – Steffen Ullrich Jan 17 '20 at 08:34
  • @SteffenUllrich this is solution my situation. It turn default with this code. Also, about SSL error I get this error when I run in office and I didn't get in home. I think the problem was with internet connection. – Ahmet Yılmaz Jan 17 '20 at 08:45
  • 1
    @AhmetYılmaz: if you use this work around for things which don't matter anyway (i.e. where you need no security) then it is fine. In all other cases please don't do it this way. – Steffen Ullrich Jan 17 '20 at 08:58