Blog | G5 Cyber Security

Secure Python Client/Server Communication

TL;DR

Use TLS (Transport Layer Security) with the ssl module in Python to encrypt communication between your client and server. This guide shows you how, using sockets for a basic example.

1. Choose Your Approach: Sockets vs. Higher-Level Libraries

You can implement secure communication directly with sockets using the ssl module, or use higher-level libraries like Flask or Django which often have built-in TLS support. This guide focuses on sockets for a fundamental understanding.

2. Server Setup (Secure Socket)

  1. Import necessary modules:
  2. import socket
    import ssl
  3. Create a socket object: Use socket.socket(socket.AF_INET, socket.SOCK_STREAM) for TCP communication.
  4. Bind the socket to an address and port: This is where your server will listen for connections.
  5. Listen for incoming connections: Use socket.listen().
  6. Create a secure context: This handles the TLS encryption. You’ll need a certificate (self-signed or from a Certificate Authority).
  7. context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) 
    context.load_cert_chain('server.crt', 'server.key')
  8. Wrap the socket with ssl.wrap_socket(): This creates a secure socket.
    secure_socket = context.wrap_socket(socket, server_side=True)
  9. Accept incoming connections: Use secure_socket.accept().
  10. Receive and send data: Use secure_socket.recv() and secure_socket.sendall() to communicate securely.
  11. Close the connection: Use secure_socket.close() when finished.

3. Client Setup (Secure Socket)

  1. Import necessary modules: Same as the server.
    import socket
    import ssl
  2. Create a socket object: Use socket.socket(socket.AF_INET, socket.SOCK_STREAM).
  3. Connect to the server’s address and port: Use socket.connect().
  4. Create a secure context (optional): For verifying the server’s certificate.
    context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) 
    context.load_verify_locations('ca.crt') # Optional: CA certificate for verification
  5. Wrap the socket with ssl.wrap_socket(): This creates a secure socket.
    secure_socket = context.wrap_socket(socket)
  6. Receive and send data: Use secure_socket.recv() and secure_socket.sendall() to communicate securely.
  7. Close the connection: Use secure_socket.close() when finished.

4. Generating Certificates (Self-Signed)

For testing, you can generate self-signed certificates using OpenSSL:

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

This creates a key (server.key) and certificate (server.crt). Do not use self-signed certificates in production! They are vulnerable to man-in-the-middle attacks.

5. Example Code Snippets

Server

import socket
import ssl

host = '127.0.0.1'
Port = 65432

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain('server.crt', 'server.key')

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind((host, Port))
socket.listen()
secure_socket = context.wrap_socket(socket, server_side=True)

conn, addr = secure_socket.accept()
with conn:
    print('Connected by', addr)
    data = conn.recv(1024)
    if data:
        print('Received:', data.decode())
        conn.sendall(b'Hello from server!')
    conn.close()

Client

import socket
import ssl

host = '127.0.0.1'
Port = 65432

context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
# context.load_verify_locations('ca.crt') # Optional: CA certificate for verification

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect((host, Port))
secure_socket = context.wrap_socket(socket)

secure_socket.sendall(b'Hello from client!')
data = secure_socket.recv(1024)
print('Received:', data.decode())
secure_socket.close()

6. Important Considerations

Exit mobile version