Skip to main content

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:

ItemTLS 1.2TLS 1.3
Handshake round trips2-RTT1-RTT
0-RTT reconnectionNot supportedSupported (use with care)
Legacy algorithmsRSA key exchange, RC4, 3DES, etc.All removed
Forward SecrecyOptionalMandatory by default
Cipher suitesDozensSimplified to 5
Attack surfaceLargeDrastically 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.