Encryption in Transit
Secure data with TLS and mutual authentication
TL;DR
TLS (Transport Layer Security) encrypts data in transit. HTTPS is HTTP over TLS. mTLS (Mutual TLS) requires both client and server to authenticate via certificates. Use TLS 1.3+ with strong cipher suites. Enforce HTTPS on all connections. Use mTLS for service-to-service communication (microservices). Certificates from trusted CAs, rotated before expiry.
Learning Objectives
- Understand TLS handshake and encryption
- Implement HTTPS for web applications
- Use mTLS for microservice authentication
- Choose appropriate cipher suites
- Manage certificate lifecycles
Motivating Scenario
Problem: API sends API keys over HTTP. Attacker on the same WiFi network intercepts traffic, steals keys. Mobile app sends user data unencrypted; ISP logs it. Microservices talk over plain HTTP; internal attacker intercepts service-to-service communication.
Solution: HTTPS (TLS) encrypts all web traffic. Attacker sees ciphertext, not keys. Microservices use mTLS; each service has certificate; mutual authentication prevents internal impersonation.
Core Concepts
TLS Handshake
Client Server
|--- ClientHello (ciphers) ------>|
|<-- ServerHello (cert, cipher) --|
|<-- ServerKeyExchange ------------|
|--- ClientKeyExchange ----------->|
|--- Finished (encrypted) -------->|
|<-- Finished (encrypted) --------|
|====== Encrypted channel ========|
- ClientHello: Client offers cipher suites and TLS versions
- ServerHello: Server selects cipher suite, sends certificate
- Key Exchange: Both derive shared secret (symmetric key)
- Finished: Both encrypt "Finished" message to verify handshake integrity
- Data Transfer: All data encrypted with symmetric key
TLS vs mTLS
- Server has certificate, proves identity
- Client verifies server certificate
- Client doesn't authenticate
- Example: HTTPS, bank websites
- Good for client-to-server (web)
- Server has certificate, proves identity
- Client has certificate, proves identity
- Both verify each other
- Requires cert management for all clients
- Good for service-to-service (microservices)
Cipher Suites
A cipher suite combines:
- Key Exchange (ECDHE): Generate shared secret
- Authentication (ECDSA): Verify certificates
- Encryption (AES-256): Encrypt data
- MAC (SHA-256): Verify data integrity
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
↑ ↑ ↑
Key Exchange Encryption MAC
Strong (2025):
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_256_GCM_SHA384
Weak (deprecated, don't use):
- TLS_RSA_WITH_AES_128_CBC_SHA (no forward secrecy)
- Any NULL cipher
Practical Examples
- HTTPS (Node.js)
- Troubleshooting & Optimization
- mTLS Server & Client
- Nginx Configuration
- Certificate Rotation
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Encrypted connection');
}).listen(443);
# Problem 1: Certificate expired
openssl x509 -in cert.pem -noout -dates
notAfter=Jan 15 10:00:00 2025 GMT # Past today's date
# Solution: Renew certificate
certbot renew --force-renewal
# Problem 2: Wrong certificate on server
openssl s_client -connect example.com:443 -servername example.com
# Look at "subject" field, ensure it matches hostname
# Problem 3: Client trust issues (certificate not signed by trusted CA)
openssl verify -CAfile ca-cert.pem client-cert.pem
# Verify returns 0 (success) or error
# Performance: Enable session resumption to skip handshake
# In Nginx:
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Enable HTTP/2 for multiplexing
listen 443 ssl http2;
# OCSP stapling (certificate revocation checking)
ssl_stapling on;
ssl_stapling_verify on;
// Server: require client certificate
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
ca: fs.readFileSync('client-ca.pem'), // Trust client certs signed by this CA
requestCert: true,
rejectUnauthorized: true // Reject clients without valid cert
};
https.createServer(options, (req, res) => {
// req.client.getPeerCertificate() contains client identity
res.writeHead(200);
res.end('mTLS connection verified');
}).listen(443);
// Client: provide certificate
const options = {
hostname: 'service.example.com',
port: 443,
path: '/api/data',
method: 'GET',
key: fs.readFileSync('client-key.pem'),
cert: fs.readFileSync('client-cert.pem'),
ca: fs.readFileSync('server-ca.pem'),
rejectUnauthorized: true
};
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
});
req.end();
server {
listen 443 ssl http2;
server_name example.com;
# Strong TLS configuration
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/private/key.pem;
# HSTS: Tell browsers to always use HTTPS
add_header Strict-Transport-Security "max-age=31536000" always;
# Optional: mTLS for specific endpoints
location /api/internal {
ssl_client_certificate /etc/ssl/certs/client-ca.pem;
ssl_verify_client on;
proxy_pass http://backend;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
# Using Let's Encrypt + Certbot (auto-rotation)
certbot certonly --webroot -w /var/www/example -d example.com
# Certbot auto-renews 30 days before expiry
# Verify renewal works
certbot renew --dry-run
# For microservices: manual cert management
# 1. Generate CSR (Certificate Signing Request)
openssl req -new -key service-key.pem -out service.csr
# 2. Sign with CA
openssl x509 -req -in service.csr \
-CA ca-cert.pem -CAkey ca-key.pem \
-CAcreateserial -out service-cert.pem \
-days 365
# 3. Deploy new cert, restart service (with zero downtime if possible)
When to Use / When Not to Use
- All HTTP connections (HTTPS standard)
- Transmitting sensitive data
- Any network communication
- APIs, databases, message queues
- Regulatory compliance (HIPAA, PCI)
- Service-to-service communication
- Microservices architectures
- Zero trust networks
- High-security internal networks
- Certificate infrastructure available
Advanced Security Patterns
Certificate Pinning for Mobile Apps
Prevent MITM even if CA is compromised.
// iOS: Pin certificate in app
import Alamofire
let pinnedCertificates = [
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
]
let evaluators: [String: ServerTrustEvaluating] = [
"api.example.com": CertificatePinningEvaluator(pinnedCertificates: pinnedCertificates)
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: serverTrustManager)
Certificate Transparency (CT) Logging
Public log of all issued certificates. Detect rogue certs.
# Check if certificate is in CT logs
openssl x509 -in cert.pem -text | grep CT
# Requires: SCT (Signed Certificate Timestamp) in certificate
Perfect Forward Secrecy (PFS)
Old recorded traffic can't be decrypted if key is compromised (ephemeral keys).
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
↑ ECDHE (Elliptic Curve Diffie-Hellman Ephemeral)
= New key per session, not reused
If RSA key is stolen, PFS ensures past sessions remain secure (attacker can't decrypt them).
Zero-Downtime Certificate Rotation
Rotate certificates without downtime.
# 1. Generate new certificate
openssl req -new -key service-key.pem -out service.csr
openssl x509 -req -in service.csr -CA ca-cert.pem -CAkey ca-key.pem \
-out service-new-cert.pem -days 365
# 2. Deploy new cert alongside old one
# Nginx can have multiple certificates:
ssl_certificate /etc/ssl/certs/service-cert-old.pem;
ssl_certificate /etc/ssl/certs/service-cert-new.pem;
# 3. Wait for all clients to have new cert (DNS TTL + grace period)
# 4. Remove old certificate
# For Kubernetes, update secret without pod restart:
kubectl create secret tls service-tls --cert=service-new-cert.pem --key=service-key.pem
kubectl set env deployment/service CERT_RELOAD=true # If app watches secret
Patterns and Pitfalls
Pitfall: Self-signed certificates (easy, but risky). Attacker can forge one. Use trusted CAs (Let's Encrypt free).
Pattern: HSTS header (Strict-Transport-Security). Tells browser: always HTTPS. Prevents downgrade attacks.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Pitfall: Weak cipher suites. Old servers use RC4, DES. Use only TLS 1.3 and strong ciphers.
Pattern: Certificate pinning for mobile apps. App only trusts specific certificate. Prevents MITM even if CA compromised.
Pitfall: Certificate expiry. Service stops accepting connections. Monitor expiry dates; auto-renew via Let's Encrypt.
# Monitor certificate expiry
openssl x509 -in cert.pem -noout -dates
# Alert if expiry under 30 days
Pattern: Separate keys per environment. Prod key never used for dev. If key compromised, only one environment affected.
Pitfall: Logging TLS keys (SSLKEYLOGFILE). Enables MITM if log is exposed. Keep keys confidential.
Design Review Checklist
- HTTPS enforced for all web connections
- TLS 1.3 or TLS 1.2 (no older versions)
- Strong cipher suites configured
- Certificates from trusted CAs
- Certificate rotation automated (Let's Encrypt or similar)
- HSTS header enabled
- Downgrade attacks prevented (redirect HTTP to HTTPS)
- mTLS for internal service-to-service communication
- Certificate pinning for mobile apps (optional)
- No self-signed certificates in production
- Regular security audits (SSL Labs test)
Self-Check
- What happens in the TLS handshake?
- Why is mTLS important for microservices?
- How would you handle certificate rotation without downtime?
TLS + mTLS = encrypted, authenticated communication that prevents eavesdropping and impersonation.
Next Steps
- Read Key Management for certificate lifecycle
- Study Network Security for defense in depth
- Explore Compliance Frameworks for regulatory requirements
References
- RFC 8446: TLS 1.3
- Mozilla SSL Configuration Generator
- OWASP Transport Layer Protection Cheat Sheet
- Let's Encrypt (Free TLS certificates)