web-dev-qa-db-fra.com

comment configurer un serveur et un client aiohttp https?

J'essaie d'apprendre comment je pourrais empêcher les données d'être modifiées après leur passage sur un réseau ouvert entre un serveur et un travailleur

dans ma tête, je pensais que cela devrait suivre quelque chose comme:

|server|---send_job----->|worker|
|      |<--send_results--|      |
|      |                 |      |
|      |-send_kill_req-->|      |

évidemment, je ne veux pas que quelqu'un modifie mon send_job pour faire quelque chose de néfaste, et je ne veux pas que quelqu'un jette un œil à mes résultats.

j'ai donc une configuration client/serveur aiohttp super simple dans laquelle j'essaie d'implémenter ssl mais je suis complètement perdu.

ci-dessous est l'essentiel que j'ai essayé, mais j'ai également essayé d'implémenter mes propres certificats SSL via:

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout domain_srv.key -out domain_srv.crt

ainsi que de suivre la documentation mais je ne suis toujours jamais en mesure de get aucune réponse du tout.

Comment pourrais-je implémenter correctement le ssl_context pour que ça marche?!

server.py

from aiohttp import web
import msgpack
import ssl

async def handle(request):
    name = request.match_info.get('name', "Anonymous")
    text = "Hello, " + name
    return web.Response(text=text)

app = web.Application()
app.add_routes([web.get('/', handle),
                web.get('/{name}', handle)])

ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
web.run_app(app, ssl_context=ssl_context)

client.py import aiohttp import asyncio import ssl

async def main():
    sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
    async with aiohttp.ClientSession() as session:
        async with session.get("https://0.0.0.0:8443", ssl=sslcontext) as response:
            html = await response.read()
            print(html)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
  1. courir python3 server.py dans une fenêtre
  2. courir python3 client.py dans une autre fenêtre

Je me retrouve ensuite généralement avec quelque chose comme:

Traceback (most recent call last):
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/connector.py", line 822, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/asyncio/base_events.py", line 804, in create_connection
    sock, protocol_factory, ssl, server_hostname)
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/asyncio/base_events.py", line 830, in _create_connection_transport
    yield from waiter
ConnectionResetError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "client.py", line 14, in <module>
    loop.run_until_complete(main())
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/asyncio/base_events.py", line 468, in run_until_complete
    return future.result()
  File "client.py", line 9, in main
    async with session.get("https://0.0.0.0:8443", ssl=sslcontext) as response:
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/client.py", line 843, in __aenter__
    self._resp = await self._coro
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/client.py", line 366, in _request
    timeout=timeout
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/connector.py", line 445, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/connector.py", line 757, in _create_connection
    req, traces, timeout)
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/connector.py", line 879, in _create_direct_connection
    raise last_exc
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/connector.py", line 862, in _create_direct_connection
    req=req, client_error=client_error)
  File "/home/mEE/miniconda3/envs/py3/lib/python3.6/site-packages/aiohttp/connector.py", line 829, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to Host 0.0.0.0:8443 ssl:<ssl.SSLContext object at 0x7fe4800d2278> [None]

Solution:

Ce fut un problème en deux parties,

  1. Je n'avais aucune idée de ce que je faisais avec openssl, la bibliothèque de requêtes m'a aidé à comprendre cela!

    import requests
    requests.get("https://0.0.0.0:8443", verify="domain_srv.crt")
    
    SSLError: HTTPSConnectionPool(Host='0.0.0.0', port=8443): Max retries exceeded with url: / (Caused by SSLError(CertificateError("hostname '0.0.0.0' doesn't match None",),))
    

    En fait, ces lignes que je viens de définir par défaut lors de la création de mes certificats openssl importaient réellement. Une configuration un peu plus correcte (mais probablement toujours erronée) similaire à

    Country Name (2 letter code) [AU]:US
    State or Province Name (full name) [Some-State]:.
    Locality Name (eg, city) []:.
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
    Organizational Unit Name (eg, section) []:.
    Common Name (e.g. server FQDN or YOUR name) []:0.0.0.0
    Email Address []:.
    

    m'a conduit au résultat:

    import requests
    requests.get("https://0.0.0.0:8443", verify="domain_srv.crt")
    
    SubjectAltNameWarning: Certificate for 0.0.0.0 has no `subjectAltName`, falling back to check for a `commonName` for now. This feature is being removed by major browsers and deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 for details.)
    

    Il semblerait que 'subjectAltName' soit quelque chose d'un peu plus difficile à ajouter, nécessitant beaucoup plus de travail qu'une simple commande, vous voudrez suivre un guide comme this , je vais l'essayer et voir si cette erreur disparaît.

  2. Je pense que j'utilisais ssl.Purpose.CLIENT/SERVER_AUTH à tort, comme @Andrej l'a mentionné, j'ai changé cela (comme je vais le montrer ci-dessous) et j'ai apporté quelques autres changements et maintenant j'obtiens les bonnes réponses. Je vais juste dire que je ne comprends toujours pas ssl.Purpose mais au moins j'ai quelque chose avec lequel je peux travailler pour le moment, et j'espère que je trouverai le reste à temps.
    client.py

    import aiohttp
    import asyncio
    import ssl
    
    
    async def main():
        sslcontext = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile='domain_srv.crt')
        async with aiohttp.ClientSession() as session:
            async with session.get("https://0.0.0.0:8443/JOHNYY", ssl=sslcontext) as response:
                html = await response.read()
                print(html)
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    

    server.py

    from aiohttp import web
    import ssl
    
    async def handle(request):
        name = request.match_info.get('name', "Anonymous")
        text = "Hello, " + name
        return web.Response(text=text)
    
    app = web.Application()
    app.add_routes([web.get('/', handle),
                    web.get('/{name}', handle)])
    
    ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_context.load_cert_chain('domain_srv.crt', 'domain_srv.key')
    web.run_app(app, ssl_context=ssl_context)
    

    commandline

    >python3 server.py
    # Switch to a new window/pane
    >python3 client.py
    b'Hello, JOHNYY'
    
10
Mr. Buttons

Vous créez les certificats mais ne les chargez pas dans la chaîne SSL. Et changez votre création ssl_context de ssl.Purpose.SERVER_AUTH à ssl.Purpose.CLIENT_AUTH:

from aiohttp import web
import ssl

async def handle(request):
    name = request.match_info.get('name', "Anonymous")
    text = "Hello, " + name
    return web.Response(text=text)

app = web.Application()
app.add_routes([web.get('/', handle),
                web.get('/{name}', handle)])


ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain('domain_srv.crt', 'domain_srv.key')

web.run_app(app, ssl_context=ssl_context)

Lorsque vous exécutez votre serveur, le client imprime lors de la connexion:

b'Hello, Anonymous'
9
Andrej Kesely