Introduction
SSL/TLS provides encryption for network communication. This tutorial covers certificate generation, HTTPS configuration, and secure connection handling in Python.
Generating Self-Signed Certificates
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import datetime
def generate_self_signed_cert(domain: str = "localhost"):
"""Generate a self-signed certificate for development."""
# Generate private key
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# Certificate subject
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Development"),
x509.NameAttribute(NameOID.COMMON_NAME, domain),
])
# Build certificate
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.datetime.utcnow())
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
.add_extension(
x509.SubjectAlternativeName([
x509.DNSName(domain),
x509.DNSName("localhost"),
x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")),
]),
critical=False,
)
.sign(key, hashes.SHA256())
)
return cert, key
# Generate and save
cert, key = generate_self_signed_cert()
# Save certificate
with open("cert.pem", "wb") as f:
f.write(cert.public_bytes(serialization.Encoding.PEM))
# Save private key
with open("key.pem", "wb") as f:
f.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
))
HTTPS with Flask
# app.py
from flask import Flask
import ssl
app = Flask(__name__)
@app.route('/')
def index():
return 'Secure Flask App!'
if __name__ == '__main__':
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('cert.pem', 'key.pem')
context.set_ciphers('ECDHE+AESGCM')
context.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
app.run(ssl_context=context, port=443)
HTTPS with FastAPI
# fastapi_https.py
from fastapi import FastAPI
import uvicorn
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Secure FastAPI"}
if __name__ == '__main__':
uvicorn.run(
app,
host="0.0.0.0",
port=443,
ssl_keyfile="key.pem",
ssl_certfile="cert.pem"
)
Secure Requests
import requests
import ssl
from urllib3.util.ssl_ import create_urllib3_context
def create_verified_session(verify_cert: bool = True):
"""Create a requests session with SSL verification."""
session = requests.Session()
if verify_cert:
session.verify = True # Use system CA bundle
else:
session.verify = './custom-ca-bundle.crt'
return session
# Custom SSL context
def create_custom_context():
"""Create custom SSL context with strong configuration."""
context = ssl.create_default_context()
context.minimum_version = ssl.TLSVersion.TLSv1_2
context.set_ciphers('ECDHE+AESGCM:ECDHE+CHACHA20')
return context
# Using httpx
import httpx
async def secure_request(url: str):
"""Make secure HTTPS request with httpx."""
async with httpx.AsyncClient(
verify=True,
timeout=30.0
) as client:
response = await client.get(url)
return response
Certificate Verification
import ssl
import socket
from cryptography import x509
from cryptography.hazmat.backends import default_backend
def verify_certificate(hostname: str, port: int = 443) -> dict:
"""Verify SSL certificate of a server."""
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert(binary_form=True)
# Parse certificate
x509_cert = x509.load_der_x509_certificate(cert, default_backend())
return {
"subject": dict(x509_cert.subject),
"issuer": dict(x509_cert.issuer),
"not_before": x509_cert.not_valid_before_utc,
"not_after": x509_cert.not_valid_after_utc,
"serial_number": x509_cert.serial_number
}
# Check certificate
result = verify_certificate("example.com")
print(f"Valid until: {result['not_after']}")
Practice Problems
- Create a client certificate for mutual TLS authentication
- Implement certificate pinning in requests
- Add automatic certificate renewal with ACME
- Configure HSTS headers for secure connections
- Implement OCSP stapling verification