【问题标题】:Python SSL Bad HandshakePython SSL 错误握手
【发布时间】:2018-11-05 16:18:23
【问题描述】:

我遇到了一个非常特殊的问题。 特别是,我想检索以下网站的内容:https://www.mycardtamoil.it/

据我了解,该网站的 SSL 证书存在一些问题。如果您在 Chrome 中打开它,则没有问题,但如果您尝试通过 cURL (curl https://www.mycardtamoil.it/) 检索内容,您会收到一个可以使用选项 -k 绕过的 ssl 错误

当我迁移到 Python3 时,我无法绕过这个问题;我测试过的代码是:

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

但我得到以下期望:

----------------------------------- ---------------------------- SysCallError Traceback(最近一次调用 最后的) C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py 在 wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname) 440 尝试: --> 441 cnx.do_handshake() 442 除了 OpenSSL.SSL.WantReadError:

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

C:\ProgramData\Anaconda3\lib\site-packages\OpenSSL\SSL.py 在 _raise_ssl_error(自我,ssl,结果)1631引发SysCallError(errno,errorcode.get(errno)) -> 1632 引发 SysCallError(-1, "Unexpected EOF") 1633 else:

SysCallError: (-1, 'Unexpected EOF')

在处理上述异常的过程中,又发生了一个异常:

SSLError Traceback(最近调用 最后的) C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py 在 urlopen(self, method, url, body, headers, retries, redirect, assert_same_host,超时,pool_timeout,release_conn,分块, body_pos, **response_kw) 600 正文=正文,标题=标题, --> 601 分块=分块) 602

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

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py 在 _validate_conn(self, conn) 849 if not getattr(conn, 'sock', None): # AppEngine 可能没有.sock --> 850 conn.connect() 第851章

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connection.py 在 连接(自我) 第325章 --> 326 ssl_context=context) 第327章

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\ssl_.py 在 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 返回 context.wrap_socket(sock, server_hostname=server_hostname) 330

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\contrib\pyopenssl.py 在 wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname) 447 除了 OpenSSL.SSL.Error 作为 e: --> 448 raise ssl.SSLError('bad handshake: %r' % e) 第449章

SSLError: ("糟糕的握手:SysCallError(-1, 'Unexpected EOF')",)

在处理上述异常的过程中,又发生了一个异常:

MaxRetryError Traceback(最近调用 最后)C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py 在发送(自我、请求、流、超时、验证、证书、代理) 第439章 --> 440 超时=超时 第441章

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\connectionpool.py 在 urlopen(self, method, url, body, headers, retries, redirect, assert_same_host,超时,pool_timeout,release_conn,分块, body_pos, **response_kw) 638 次重试 = retries.increment(方法,url,错误=e,_pool=self, --> 639 _stacktrace=sys.exc_info()[2]) 640 次重试.sleep()

C:\ProgramData\Anaconda3\lib\site-packages\urllib3\util\retry.py 在 增量(自我、方法、url、响应、错误、_pool、_stacktrace) 387 如果 new_retry.is_exhausted(): --> 388 引发 MaxRetryError(_pool, url, error or ResponseError(cause)) 第389章

MaxRetryError: HTTPSConnectionPool(host='www.mycardtamoil.it', 端口 = 443):最大重试次数超出 url:/(由 SSLError(SSLError(“错误的握手:SysCallError(-1,'意外 EOF')",),))

在处理上述异常的过程中,又发生了一个异常:

SSLError Traceback(最近调用 最后)在() 1 导入请求 ----> 2 response = requests.get('https://www.mycardtamoil.it/', verify=False)

C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py in get(url, 参数,**kwargs) 70 71 kwargs.setdefault('allow_redirects',真) ---> 72 返回请求('get', url, params=params, **kwargs) 73 74

C:\ProgramData\Anaconda3\lib\site-packages\requests\api.py 在 请求(方法,网址,**kwargs) 56 # 个案例,在其他案例中看起来像是内存泄漏。 57 与 session.Session() 作为会话: ---> 58 返回 session.request(method=method, url=url, **kwargs) 59 60

C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py 在 request(self, method, url, params, data, headers, cookies, files, 身份验证、超时、allow_redirects、代理、挂钩、流、验证、证书、 json) 第506章 第507章 --> 508 resp = self.send(prep, **send_kwargs) 509 510返回响应

C:\ProgramData\Anaconda3\lib\site-packages\requests\sessions.py 在 发送(自我,请求,**kwargs) 616 617 # 发送请求 --> 618 r = adapter.send(request, **kwargs) 619 620 # 请求总耗时(大约)

C:\ProgramData\Anaconda3\lib\site-packages\requests\adapters.py 在 发送(自我、请求、流、超时、验证、证书、代理) 504 如果是实例(e.reason,_SSLError): 505 # 此分支适用于 urllib3 v1.22 及更高版本。 --> 506 引发 SSLError(e, request=request) 507 508 引发 ConnectionError(e,request=request)

SSLError: HTTPSConnectionPool(host='www.mycardtamoil.it', port=443): url 超出最大重试次数:/(由 SSLError(SSLError(“bad 握手:SysCallError(-1, 'Unexpected EOF')",),))

有人可以帮助我了解如何使用 requests 模块修复它吗?

提前致谢, 齐射

【问题讨论】:

  • 你用反斜杠结束你的字符串。转义反斜杠。 a = '\' 会报错。 a='\\' 没关系
  • 什么意思?我正在使用不需要转义的正斜杠。我错了吗?
  • 对不起,是的,你是对的。

标签: python python-3.x ssl curl python-requests


【解决方案1】:

根据SSLLabs,服务器的设置很糟糕。值得注意的是,它仅支持 TLS 1.0 及更低版本(甚至是或多或少损坏的 SSLv3 和绝对损坏的 SSLv2),并且它也仅支持被认为是弱密码或真正不安全的密码。

虽然客户端通常支持 TLS 1.0(尽管存在已知问题,但仍被认为足够安全),但它们通常不支持弱和不安全的密码 - 至少在默认情况下是这样,但有时它们甚至不再编译。服务器支持的不太安全的密码可能是 TLS_RSA_WITH_3DES_EDE_CBC_SHA(在 OpenSSL 中称为 DES-CBC3-SHA)。

假设此密码在您的 Python 使用的 OpenSSL 版本中仍然可用,您可以破解请求以启用此密码。基于this question,可以这样完成:

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

虽然它现在不再得到 Unexpected EOF,但它得到另一个错误:certificate verify failed。这是因为服务器设置不仅在协议版本和密码方面被破坏,而且证书配置不正确。 SSLLabs report 还显示了所有其他问题

此服务器的证书链不完整。

添加verify=False 就像您通过添加更多不安全性来“修复”问题一样,即它跳过了证书的验证。请参阅here,了解如何正确解决此类情况。虽然,在您必须处理严重损坏且不安全的系统的情况下,正确检查证书是否真的会显着提高安全性尚不清楚。无论是否使用 HTTPS,我都建议不要向该系统发送任何敏感数据。

【讨论】:

  • 感谢您非常清楚的解释。现在它起作用了。正如您所强调的,此服务器配置非常不安全。我会避免按照您的建议发送任何敏感数据
  • @Steffen Ullrich 我在我的代码中写了 'requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DES-CBC3-SHA' '。但我收到错误 no chiper match。我怎样才能再次默认?
  • @AhmetYılmaz:我不知道你想做什么。仅在需要时才应显式覆盖默认密码,因为相关密码不在其中。如果您想使用 Python 中的默认密码,请不要覆盖默认密码。
  • @AhmetYılmaz:这还没有“解决”。这是使用看似有效的代码解决的问题,该代码也存在允许可怕的不安全密码的问题。请注意,在处理安全性时,它并不意味着它只是工作就安全。
  • @AhmetYılmaz:如果您将这项工作用于无关紧要的事情(即您不需要安全性的地方),那很好。在所有其他情况下,请不要这样做。