Advanced TLS: TLS 1.3 and Disabling Weak Ciphers
Modern TLS configuration goes beyond simply turning on encryption — it means removing vulnerable algorithms, guaranteeing Perfect Forward Secrecy, and enabling the latest protocol version.
Advantages of TLS 1.3
TLS 1.3 was standardized as RFC 8446 in 2018. Compared to TLS 1.2:
| Item | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Handshake round trips | 2-RTT | 1-RTT |
| 0-RTT reconnection | Not supported | Supported (use with care) |
| Legacy algorithms | RSA key exchange, RC4, 3DES, etc. | All removed |
| Forward Secrecy | Optional | Mandatory by default |
| Cipher suites | Dozens | Simplified to 5 |
| Attack surface | Large | Drastically reduced |
TLS 1.3-Only Configuration (Nginx)
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/privkey.pem;
# TLS 1.3 only (best security, lower compatibility)
ssl_protocols TLSv1.3;
# TLS 1.3 cipher suites are selected automatically by OpenSSL
# Manual override (OpenSSL 1.1.1+):
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
}
Practical recommendation (TLS 1.2 + 1.3):
ssl_protocols TLSv1.2 TLSv1.3;
Older devices (Android 4.x, IE 11, etc.) may not support TLS 1.3.
Disabling Weak Ciphers
Algorithms to Remove
RC4 — vulnerable to NOMORE attack
3DES — vulnerable to SWEET32 attack (64-bit block size)
MD5 — collision risk
SHA-1 — collision risk (SHAttered)
NULL — no encryption
EXPORT — 40–56-bit keys (extremely weak)
aNULL — no authentication
eNULL — no encryption
DES — single DES (weak)
IDEA — obsolete
SEED — Korean standard, removed from TLS
Nginx — Safe Cipher Suite
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:'
'DHE-RSA-AES128-GCM-SHA256:'
'DHE-RSA-AES256-GCM-SHA384:'
'!DSS:'
'!aNULL:'
'!eNULL:'
'!EXPORT:'
'!RC4:'
'!3DES:'
'!MD5:'
'!PSK:'
'!aECDH';
Apache — Safe Cipher Suite
SSLCipherSuite 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:\
DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:\
!DSS:!aNULL:!eNULL:!EXPORT:!RC4:!3DES:!MD5
SSLHonorCipherOrder off # off for TLS 1.3
Perfect Forward Secrecy (PFS)
Allowing only ECDHE or DHE key exchange guarantees PFS. Cipher suites starting with ECDHE- in the list above all provide PFS.
# Check if the server supports PFS
openssl s_client -connect example.com:443 2>/dev/null | grep "Server Temp Key"
# Server Temp Key: X25519, 253 bits ← PFS supported (ECDHE)
# Server Temp Key: DH, 4096 bits ← PFS supported (DHE)
# (nothing) ← PFS not supported (RSA key exchange)
0-RTT (TLS 1.3 Early Data)
With TLS 1.3, a client reconnecting to a previously visited server can send data immediately without a handshake. Performance improves, but there is a replay attack risk.
# Disable 0-RTT (security first — this is the default)
ssl_early_data off;
# Enable 0-RTT (only when GET requests are the only use case)
ssl_early_data on;
# The application MUST check the Early-Data header
# Replay defense when 0-RTT is enabled (Nginx)
location / {
if ($ssl_early_data) {
# Return 425 (Too Early) for Early Data requests
return 425;
}
proxy_pass http://backend;
}
Rule: Never use 0-RTT for financial transactions, payment APIs, or any state-mutating endpoints.
DH Parameters (for TLS 1.2 DHE)
When using DHE key exchange in TLS 1.2, safe DH parameters are required. Nginx's default is 1024-bit, which is weak.
# Generate 4096-bit DH parameters (takes time)
openssl dhparam -out /etc/nginx/dhparam.pem 4096
# Or use standard parameters (recommended, instant)
openssl dhparam -out /etc/nginx/dhparam.pem 2048
ssl_dhparam /etc/nginx/dhparam.pem;
Check TLS Support by OpenSSL Version
# Check system OpenSSL version
openssl version -a
# Verify TLS 1.3 support
openssl s_client -connect example.com:443 -tls1_3 2>&1 | grep "Protocol"
# Check Nginx's OpenSSL version
nginx -V 2>&1 | grep "OpenSSL"
# OpenSSL 3.0.x : TLS 1.3, 0-RTT supported
# OpenSSL 1.1.1 : TLS 1.3 supported
# OpenSSL 1.0.2 : TLS 1.3 NOT supported (upgrade required)
Vulnerability Diagnostic Tool: testssl.sh
# Install testssl.sh
git clone --depth 1 https://github.com/drwetter/testssl.sh.git
cd testssl.sh
# Full scan
./testssl.sh example.com
# Targeted scans
./testssl.sh --protocols example.com # Protocol versions
./testssl.sh --ciphers example.com # Cipher suites
./testssl.sh --vulnerable example.com # Known vulnerabilities (POODLE, BEAST, etc.)
./testssl.sh --headers example.com # Security headers
./testssl.sh --client-simulation example.com # Client compatibility
Sample output:
Protocol Support
SSLv2 not offered (OK)
SSLv3 not offered (OK)
TLS 1 not offered (OK)
TLS 1.1 not offered (OK)
TLS 1.2 offered (OK)
TLS 1.3 offered (OK)
SSL Labs Test Checklist
To achieve an A+ grade at ssllabs.com:
✅ TLS 1.0 and 1.1 disabled
✅ SSL 2.0 and 3.0 disabled
✅ Weak ciphers (RC4, 3DES, EXPORT) disabled
✅ Forward Secrecy (ECDHE/DHE) supported
✅ HSTS configured (max-age >= 180 days)
✅ Secure certificate chain (2048-bit+ RSA or 256-bit+ ECDSA)
✅ OCSP Stapling enabled
✅ HTTP/2 enabled
The next page covers SSL Labs A+ achievement and automated certificate expiry monitoring.