SSL 错误握手错误 10054“WSAECONNRESET”

Posted

技术标签:

【中文标题】SSL 错误握手错误 10054“WSAECONNRESET”【英文标题】:SSL bad Handshake Error 10054 "WSAECONNRESET" 【发布时间】:2016-12-10 05:05:54 【问题描述】:

注意事项:

versions

Python 2.7.11 and my requests version is '2.10.0'
'OpenSSL 1.0.2d 9 Jul 2015'
Please read the below comment by Martijn Pieters before reproducing 

最初我尝试使用以下代码从https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx 获取 pdf

code1:

>>> import requests
>>> requests.get("https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx",verify=False)

错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\api.py", line 67, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\api.py", line 53, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\adapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(10054, 'WSAECONNRESE
T')",)

经过谷歌搜索,我发现您已使用 SSL 验证,并且使用带有适配器的会话可以解决问题。但是我仍然有错误,请在下面找到代码和错误

代码2:

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
import ssl
import traceback

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)


s = requests.Session()
s.mount('https://', MyAdapter())
print "Mounted    "
r = s.get("https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx", stream=True, timeout=120)

错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 480, in get
    return self.request('GET', url, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\adapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(10054, 'WSAECONNRESET')",)

【问题讨论】:

您能否指定您正在使用的请求版本以及 Python 的确切版本?我设法在请求 2.10.0 的 Python 3.5 中运行您的第二个代码示例而没有问题。您能否也看看this 答案,它建议猴子修补ssl.wrap_socket() 你用的是什么版本的openssl? 我很喜欢赏金,但我没有想出答案,将其标记为重复项才公平。 对那些试图复制的人的重要提示:Python 2.7.9 和更新版本显着升级了 Python 的 SSL 功能。见PEP 466。如果您想帮助重现并找到解决方案,则必须使用至少是新版本的版本。 (在 OS X 上,使用 Homebrew 构建的 Python 作为Apple's system Python uses an outdated OpenSSL version)。 @The6thSense 这很有道理。从您的 Windows 机器上,我建议 Martijn 可能是正确的,并且您遇到了防火墙问题(甚至可能是 Windows 防火墙),因为that error 表示套接字已被对等方断开连接。当您在服务器上运行并看到“证书验证失败”错误时,可能是因为远端证书存在问题 - 除了忽略它之外,您无能为力。 【参考方案1】:

首先,我确认无法从任何地方访问主机www.neco.navy.mil。从某些网络(地理)它可以工作*,从其他网络连接只是挂起:

$ curl www.neco.navy.mil
curl: (7) couldn't connect to host
$ curl https://www.neco.navy.mil
curl: (7) couldn't connect to host

二、能建立连接时存在证书问题:

$ curl -v https://www.neco.navy.mil
* Rebuilt URL to: https://www.neco.navy.mil/
* Hostname was NOT found in DNS cache
*   Trying 205.85.2.133...
* Connected to www.neco.navy.mil (205.85.2.133) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

为确保,您只需将其提供给Qualys SSL tester:

CA (DoD Root CA 2) 不受信任。此外,它不在链中。注意OpenSSL validation process needs whole chain:

首先建立一个证书链,从提供的证书开始,到根 CA 结束。如果整个链条无法建立起来就是错误的。

但只有 www.neco.navy.mil -> DODCA-28。它可能与 TLD 和额外的安全措施有关,但 C 级本身并不多 ;-)

在 Python 方面,它不会有太大的不同。如果您无权访问 CA,则只能完全禁用证书验证(当然,在您解决连接问题之后)。如果有的话,可以使用cafile

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import urllib2
import ssl


ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

r = urllib2.urlopen('https://www.neco.navy.mil/'
  'necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx', 
  timeout = 5, context = ctx)
print(len(r.read()))

r = urllib2.urlopen('https://www.neco.navy.mil/'
  'necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx', 
  timeout = 5, cafile = '/path/to/DODCA-28_and_DoD_Root_CA_2.pem')
print(len(r.read()))

要使用特定版本的 Python 重现,请使用如下简单的 Dockerfile:

FROM python:2.7.11

WORKDIR /opt
ADD . ./

CMD dpkg -s openssl | grep Version && ./app.py

然后运行:

docker build -t ssl-test .
docker run --rm ssl-test

【讨论】:

【参考方案2】:

这个 sn-p 在 windows7 上为我工作(py2.7.11 64bits + requests==2.10.0):

import requests
import ssl
import traceback
import shutil
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager


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)


if __name__ == "__main__":
    s = requests.Session()
    s.mount('https://', MyAdapter())
    print "Mounted    "
    filename = "N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx"
    r = s.get(
        "https://www.neco.navy.mil/necoattach/0".format(filename), verify=False, stream=True, timeout=120)

    if r.status_code == 200:
        with open(filename, 'wb') as f:
            r.raw.decode_content = True
            shutil.copyfileobj(r.raw, f)

【讨论】:

确实如此,但我需要详细解释原因以及解决方法【参考方案3】:

我使用 python 2.7.6,这个简单的例子仍在我的 ubuntu 14.04 上运行

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

with open('out.docx', 'wb') as h :
    r = requests.get("https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx", verify=False, stream=True)

    for block in r.iter_content(1024):
        h.write(block)

【讨论】:

抛出错误EOF occurred in violation of protocol (_ssl.c:590)后无法正常工作 这对我有用(即使没有禁用警告)。我看到了 docx,它可以通过说明列表打开。 @JRichardSnape 我不知道为什么,但它给我抛出了 EOF 错误 2.7.9 之前的 Python 2.7 版本确实公开了足够的 OpenSSL 功能来正确验证 SSL 证书。使用 2.7.11 的 OP,如果您想开始证明您可以使其工作,您将必须升级到更新的 Python 版本。 @JRichardSnape:什么版本的 Python?请在此处尝试使用 2.7.9 或更高版本。

以上是关于SSL 错误握手错误 10054“WSAECONNRESET”的主要内容,如果未能解决你的问题,请参考以下文章

OpenSSL SSL_read: Connection was reset, errno 10054 错误解决

git 操作 提示OpenSSL SSL_read: Connection was reset, errno 10054错误

Git报错解决:OpenSSL SSL_read: Connection was reset, errno 10054 错误解决

Git报错解决:OpenSSL SSL_read: Connection was reset, errno 10054 错误解决

错误记录PyCharm 中从 GitHub 中 Clone 代码到本地报错 ( OpenSSL SSL_read: Connection was reset, errno 10054 )(

解决 OpenSSL SSL_read: Connection was reset, errno 10054的问题