requests 和 aiohttp 中解决ssl错误


requestsaiohttp中解决ssl错误


某些网站对 ssl 1.0 以上的版本支持并不友好,但是 python ssl lib 默认会指定当前OpenSSL支持的最高版本,并且当服务器返回的ssl版本号低于或者等于1.0时, 会出现如下错误

aiohttp

aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host facebook.com:443 ssl:[None]

requests

 Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:645)SSLErrorEOF occurred in violation of protocol 

查看当前client的ssl版本

python -c "import ssl; print(ssl.OPENSSL_VERSION)"

查看本地 openssl version

openssl version

查看通讯过程使用的额ssl

OpenSSL> s_client  -connect www.facebook.com:443 -msg
   

SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-ECDSA-AES128-GCM-SHA256
    Session-ID: 3D78B4E33A5376E697C95E9ADD1E4BFDBB69A564EDE7F262E5D4A6D6D96AAE2B
    Session-ID-ctx:
    Master-Key: 5F8B981090E231DEF760DC0A1F5DCBBB258B62A288A5706FBE86719BAD6E25ED4F68B0F362FDDDD095AF67CA3754E105
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    TLS session ticket lifetime hint: 172800 (seconds)
    TLS session ticket:
    0000 - 7f 42 fc d9 b1 f2 9d 96-6d ef a4 45 cb 27 c7 95   .B......m..E.'..
    0010 - fc 91 58 79 77 4b ef 3b-a3 0b 43 14 3e 51 83 27   ..XywK.;..C.>Q.'
    0020 - a5 0a 53 a6 1f 06 d3 cd-d6 b3 0d 4f a0 5f a0 bc   ..S........O._..
    0030 - 5b f8 25 5e 69 77 df 75-7f fc 76 44 eb 5d 26 6d   [.%^iw.u..vD.]&m
    0040 - cc e7 0b 84 b2 6e 4d 6c-f4 33 89 55 a5 69 58 fc   .....nMl.3.U.iX.
    0050 - bd c1 51 8d 70 2c 52 47-c5 31 b3 66 47 4e 13 18   ..Q.p,RG.1.fGN..
    0060 - 65 4a f9 48 71 34 50 12-7f 9a 6c 8d 01 11 9b 25   eJ.Hq4P...l....%
    0070 - e9 42 b4 61 59 60 0f 0e-59 38 54 1c dd 32 f6 ce   .B.aY`..Y8T..2..
    0080 - 69 b9 be a2 be 17 5a e3-69 f2 db ab b2 2f ca 3e   i.....Z.i..../.>
    0090 - 79 87 2d a0 e2 d7 93 15-77 34 86 53 3d c4 13 8a   y.-.....w4.S=...
    00a0 - 12 73 59 22 24 d7 49 84-63 4d 5d 9b 2f b7 12 26   .sY"$.I.cM]./..&

    Start Time: 1556282230
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
<<< TLS 1.2 Alert [length 0002], warning close_notify
    01 00
closed
>>> TLS 1.2 Alert [length 0002], warning close_notify
    01 00

curl 和 aiohttp , requests等其他库默认使用安全的 ssl/tls 版本

curl is designed to use a "safe version" of SSL/TLS by default. It means that it will not negotiate SSLv2 or SSLv3 unless specifically told to,
and in fact several TLS libraries no longer provide support for those protocols so in many cases curl is not even able to speak those protocol versions 
unless you make a serious effort.

修改ssl_version



class MyAdapter(HTTPAdapter):
    # 使用  TLSv1  Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:645)SSLErrorEOF occurred in violation of protocol
    def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=ssl.PROTOCOL_TLSv1
        )

    #  s=requests.session()
    # s.mount("https://", MyAdapter)



class SSLAdapter(HTTPAdapter):
    '''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
    def __init__(self, ssl_version=None, **kwargs):
        self.ssl_version = ssl_version

        super(SSLAdapter, self).__init__(**kwargs)

    def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
        self.poolmanager = PoolManager(num_pools=connections,
                                       maxsize=maxsize,
                                       block=block,
                                       ssl_version=self.ssl_version)


import ssl
import aiohttp
import asyncio
 
 
async def test():
    FORCED_CIPHERS = (
        'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
        'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES'
    )
    sslcontext = ssl.create_default_context()
    sslcontext.options |= ssl.OP_NO_SSLv3
    sslcontext.options |= ssl.OP_NO_SSLv2
    sslcontext.options |= ssl.OP_NO_TLSv1_1
    sslcontext.options |= ssl.OP_NO_TLSv1_2
    sslcontext.options |= ssl.OP_NO_TLSv1_3
    sslcontext.set_ciphers(FORCED_CIPHERS)
 
    async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=50, loop=loop)) as session:
        r = await session.get('https://www.mdnkids.com/news/?Serial_NO=108552', ssl=sslcontext)
        print(await r.text())
 
if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(test())


Buy me a 肥仔水!