Encrypt connections¶
You should always secure WebSocket connections with TLS (Transport Layer Security).
TLS vs. SSL
TLS is sometimes referred to as SSL (Secure Sockets Layer). SSL was an earlier encryption protocol; the name stuck.
The wss
protocol is to ws
what https
is to http
.
Secure WebSocket connections require certificates just like HTTPS.
Configure the TLS context securely
The examples below demonstrate the ssl
argument with a TLS certificate
shared between the client and the server. This is a simplistic setup.
Please review the advice and security considerations in the documentation of
the ssl
module to configure the TLS context appropriately.
Servers¶
In a typical deployment, the server is behind a reverse proxy that terminates TLS. The client connects to the reverse proxy with TLS and the reverse proxy connects to the server without TLS.
In that case, you don’t need to configure TLS in websockets.
If needed in your setup, you can terminate TLS in the server.
In the example below, serve()
is configured to receive
secure connections. Before running this server, download
localhost.pem
and save it in the
same directory as server.py
.
#!/usr/bin/env python
import asyncio
import pathlib
import ssl
from websockets.asyncio.server import serve
async def hello(websocket):
name = await websocket.recv()
print(f"<<< {name}")
greeting = f"Hello {name}!"
await websocket.send(greeting)
print(f">>> {greeting}")
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
ssl_context.load_cert_chain(localhost_pem)
async def main():
async with serve(hello, "localhost", 8765, ssl=ssl_context) as server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(main())
Receive both plain and TLS connections on the same port isn’t supported.
Clients¶
connect()
enables TLS automatically when connecting to a
wss://...
URI.
This works out of the box when the TLS certificate of the server is valid, meaning it’s signed by a certificate authority that your Python installation trusts.
In the example above, since the server uses a self-signed certificate, the client needs to be configured to trust the certificate. Here’s how to do so.
#!/usr/bin/env python
import pathlib
import ssl
from websockets.sync.client import connect
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
ssl_context.load_verify_locations(localhost_pem)
def hello():
uri = "wss://localhost:8765"
with connect(uri, ssl=ssl_context) as websocket:
name = input("What's your name? ")
websocket.send(name)
print(f">>> {name}")
greeting = websocket.recv()
print(f"<<< {greeting}")
if __name__ == "__main__":
hello()