Introduction

TLS Configuration Guide

Transport Layer Security (TLS) is the foundation of secure internet communication. However, TLS is only as strong as its configuration. Weak cipher suites, outdated protocol versions, and missing security headers leave connections vulnerable to downgrade attacks, protocol flaws, and traffic interception.

Cipher Suites

A cipher suite defines the cryptographic algorithms used for key exchange, authentication, encryption, and message authentication.

Modern Nginx TLS configuration

server {

listen 443 ssl http2;

server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Modern cipher suite selection

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;

ssl_prefer_server_ciphers off; # Let client negotiate for TLS 1.3

Modern key exchange

ssl_ecdh_curve X25519:prime256v1:secp384r1;

OCSP stapling

ssl_stapling on;

ssl_stapling_verify on;

resolver 1.1.1.1 8.8.8.8 valid=300s;

resolver_timeout 5s;

}

Cipher Suite Breakdown

ECDHE - Ephemeral Diffie-Hellman (forward secrecy)

ECDSA - Elliptic Curve Digital Signature Algorithm (authentication)

AES128 - AES with 128-bit key (symmetric encryption)

GCM - Galois/Counter Mode (authenticated encryption)

SHA256 - SHA-256 HMAC (integrity)

Deprecated Ciphers

NEVER use these

ssl_protocols SSLv3 TLSv1 TLSv1.1; # All broken

ssl_ciphers RC4:3DES:EXPORT:NULL; # Weak or broken

HSTS (HTTP Strict Transport Security)

HSTS instructs browsers to always connect via HTTPS, preventing SSL stripping attacks.

Strict HSTS for production

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

Explanation:

max-age=63072000 - 2 years in seconds

includeSubDomains - Applies to all subdomains

preload - Allow inclusion in browser preload lists

Flask HSTS implementation

from flask import Flask, make_response

app = Flask(name)

@app.after_request

def add_security_headers(response):

if request.is_secure:

response.headers['Strict-Transport-Security'] = \

'max-age=63072000; includeSubDomains; preload'

return response

Certificate Pinning

While HTTP Public Key Pinning (HPKP) is deprecated, certificate pinning techniques remain useful in controlled environments.

TLS fingerprint validation (alternative to deprecated HPKP)

import ssl

import hashlib

import requests

from cryptography import x509

from cryptography.hazmat.primitives import hashes

def validate_certificate_fingerprint(hostname, port=443, expected_hash=None):

cert_pem = ssl.get_server_certificate((hostname, port))

cert = x509.load_pem_x509_certificate(cert_pem.encode())

Calculate SHA-256 fingerprint

fingerprint = cert.fingerprint(hashes.SHA256())

fingerprint_hex = fingerprint.hex()

if expected_hash and fingerprint_hex != expected_hash:

raise ValueError(

f"Certificate fingerprint mismatch for {hostname}: "

f"expected {expected_hash}, got {fingerprint_hex}"

)

return fingerprint_hex

Usage: pin to expected fingerprint

PINNED_FINGERPRINTS = {

'api.example.com': 'a1b2c3d4e5f6...',

}

TLS 1.3 Benefits

TLS 1.3 simplifies the handshake to one round trip (or zero with pre-shared keys), removes insecure features, and mandates forward secrecy.

Test TLS 1.3 support

openssl s_client -connect example.com:443 -tls1_3

Testing with SSL Labs

Using ssllabs-scan

docker run --rm -t jumanjiman/ssllabs-scan example.com

Using testssl.sh

testssl.sh --quiet --htmlfile report.html example.com

Quick curl-based check

curl -sI https://example.com | grep -i "strict-transport-security|x-frame-options|content-security-policy"

Full Hardened Configuration

/etc/nginx/conf.d/ssl.conf - hardened TLS

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;

ssl_prefer_server_ciphers off;

ssl_ecdh_curve X25519:prime256v1:secp384r1;

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 1d;

ssl_session_tickets off;

OCSP Stapling

ssl_stapling on;

ssl_stapling_verify on;

resolver 1.1.1.1 8.8.8.8 valid=300s;

Security Headers

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

add_header X-Content-Type-Options nosniff always;

add_header X-Frame-Options DENY always;

Conclusion

A proper TLS configuration requires modern protocol versions (TLS 1.2 and 1.3), forward-secrecy cipher suites, HSTS enforcement, and regular testing with tools like SSL Labs and testssl.sh. Disable all legacy protocols and ciphers, enable OCSP stapling for performance, and consider certificate pinning for high-security APIs.