Ошибка SSL плохое рукопожатие 10054 " WSAECONNRESET"

Примечания:

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 

Первоначально я пытался получить pdf из https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx использовать код, как показано ниже

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:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestsapi.py", line 67, in get
    return request('get', url, params=params, **kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestsapi.py", line 53, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestssessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestssessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestsadapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(10054, 'WSAECONNRESE
T')",)

после googling и поиска я обнаружил, что вы используете проверку SSL и использование сеанса с адаптерами может решить проблему. Но у меня все еще есть ошибка, пожалуйста, найдите код и ошибку ниже

Code2:

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:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestssessions.py", line 480, in get
    return self.request('GET', url, **kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestssessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestssessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "C:Usersmob140003207AppDataLocalEnthoughtCanopyUserlibsite-packa
gesrequestsadapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(10054, 'WSAECONNRESET')",)

3 ответов


прежде всего, я подтверждаю, что хозяин,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.

чтобы убедиться, вы просто кормите его тестер SSL Qualys: enter image description here

CA (DoD Root CA 2) не доверять. Причем это не в цепь. Обратите внимание, что процесс проверки OpenSSL требует всей цепочки:

во-первых, цепочка сертификатов строится, начиная с предоставленного сертификата и заканчивая корневым ЦС. Это ошибка, если вся цепь не может быть построена.

но есть только www.neco.navy.mil -> ДОДКА-28. Это может быть связано с TLD и дополнительной мерой безопасности, но только класс C не так много; -)

на они на стороне питона, это не будет сильно отличаться. Если у вас нет доступа к ЦС, вы можете полностью отключить проверку сертификата (после решения проблемы подключения, конечно). Если у вас есть, вы можете использовать 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

этот фрагмент работает для меня (py2.7.11 64bits + запросы==2.10.0) на windows7:

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)

Я использую 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)