How to Configure SSL in Aiohttp with OpenSSL

In this tutorial, you’ll learn how to configure SSL in Aiohttp using OpenSSL.

You’ll create self-signed certificates, set up SSL contexts, and implement secure connections for both servers and clients.

 

 

Create Self-signed Certificate using OpenSSL

Generate Private Key

To generate a private key, you can use the following OpenSSL command:

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

This command generates a 2048-bit RSA private key and saves it to the file private_key.pem.

Create Certificate Signing Request (CSR)

Next, create a certificate signing request using the generated private key:

openssl req -new -key private_key.pem -out csr.pem

Output:

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:San Francisco
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Corp
Organizational Unit Name (eg, section) []:IT Department
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:admin@local

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

This interactive process creates a CSR file named csr.pem.

Self-sign the Certificate

To self-sign the certificate using the CSR and private key, use this command:

openssl x509 -req -days 365 -in csr.pem -signkey private_key.pem -out certificate.pem

Output:

Signature ok
subject=C = US, ST = California, L = San Francisco, O = Example Corp, OU = IT Department, CN = localhost, emailAddress = admin@local
Getting Private key

This command generates a self-signed certificate valid for 365 days and saves it as certificate.pem.

 

Configure SSL context

To create an SSL context object in Python, use the following code:

import ssl
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)

This creates a default SSL context for client authentication.

Load Certificate and Private key

Load the certificate and private key into the SSL context:

ssl_context.load_cert_chain(certfile='certificate.pem', keyfile='private_key.pem')

This code loads the certificate and private key files into the SSL context.

Set SSL protocols and ciphers

To set specific SSL protocols and ciphers, use the following code:

ssl_context.set_ciphers('ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256')
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2

This code sets the cipher suite to use ECDHE-RSA with AES256 or AES128 in GCM mode, and uses TLS version 1.2 for improved security.

 

Implement SSL in Aiohttp Server

To configure an Aiohttp server to use SSL, modify your server setup code:

from aiohttp import web
async def hello(request):
    return web.Response(text="Hello, secure world!")
app = web.Application()
app.add_routes([web.get('/', hello)])
web.run_app(app, ssl_context=ssl_context)

When you visit https://127.0.0.1:8443 and accept the warning you’ll see Hello world message.

 

Client-side SSL configuration

To create an SSL-enabled client session in Aiohttp, use the following code:

import aiohttp
import ssl
import asyncio
async def fetch():
    ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
    ssl_context.load_verify_locations('certificate.pem')
    async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=ssl_context)) as session:
        async with session.get('https://localhost:8443') as response:
            print(response.status)
            print(await response.text())
asyncio.run(fetch())

Output:

200
Hello, secure world!

This code creates a client session with SSL enabled and verifies the server certificate.

 

Handle SSL in WebSockets

To create a secure WebSocket server, modify your WebSocket handler:

from aiohttp import web
import ssl
async def websocket_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)
    async for msg in ws:
        if msg.type == web.WSMsgType.TEXT:
            await ws.send_str(f"You said: {msg.data}")
        elif msg.type == web.WSMsgType.ERROR:
            print(f'WebSocket connection closed with exception {ws.exception()}')
    return ws
app = web.Application()
app.add_routes([web.get('/ws', websocket_handler)])
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(certfile='certificate.pem', keyfile='private_key.pem')
web.run_app(app, ssl_context=ssl_context)

This code sets up a secure WebSocket server using the SSL context we created earlier.

Implement SSL for websocket clients

To create a secure WebSocket client, use the following code:

import asyncio
import ssl
import aiohttp
async def main():
    ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
    ssl_context.load_verify_locations('certificate.pem')
    async with aiohttp.ClientSession() as session:
        async with session.ws_connect('wss://localhost:8443/ws', ssl=ssl_context) as ws:
            await ws.send_str("Hello, secure WebSocket!")
            async for msg in ws:
                if msg.type == aiohttp.WSMsgType.TEXT:
                    print(f"Received: {msg.data}")
                elif msg.type == aiohttp.WSMsgType.CLOSED:
                    break
                elif msg.type == aiohttp.WSMsgType.ERROR:
                    break
asyncio.run(main())

Output back from the server:

Received: You said: Hello, secure WebSocket!

This code creates a secure WebSocket client that connects to a WSS (WebSocket Secure) endpoint using the SSL context.

Leave a Reply

Your email address will not be published. Required fields are marked *