Harden TLS Cipher Suites
Restrict a server to modern TLS versions and strong ciphers, then verify with a scanner and client handshake tests.
Task
Configure a server to offer only TLS 1.2 and 1.3 with strong cipher suites.
When to use this
A scanner reports legacy protocol support, exposing clients to downgrade attacks and weak cipher negotiation.
Prerequisites
- Control over the TLS terminator
- openssl for handshake tests
- A scanner such as testssl.sh
Steps
1. Set modern protocols and cipher lists.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;Expected output: Only TLS 1.2 and 1.3 with forward-secret AEAD suites are offered.
2. Verify the negotiated protocol and cipher.
openssl s_client -connect app.example.com:443 -tls1_1 </dev/null 2>&1 | grep -i 'no protocols\|alert'
openssl s_client -connect app.example.com:443 -tls1_3 </dev/null 2>&1 | grep -i 'Protocol\|Cipher'Expected output: Legacy TLS is refused while TLS 1.3 negotiates a strong AEAD suite.
Troubleshooting
Problem
Legacy clients break
Solution
Document the client matrix and provide a separate endpoint only if a compliance reason exists.
Problem
Cipher list rejected
Solution
Check the terminator syntax; some expect OpenSSL names, others IANA names.
Limitations
- Breaking legacy clients is a compatibility decision.
- Does not cover certificate or key strength.
- Cipher preference interacts with HTTP/2 requirements.
What this recipe does
Configure a server to offer only TLS 1.2 and 1.3 with strong cipher suites.
A scanner reports legacy protocol support, exposing clients to downgrade attacks and weak cipher negotiation.
Prerequisites
- Control over the TLS terminator
- openssl for handshake tests
- A scanner such as testssl.sh
Procedure
- Set modern protocols and cipher lists.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;
Expected result: Only TLS 1.2 and 1.3 with forward-secret AEAD suites are offered.
- Verify the negotiated protocol and cipher.
openssl s_client -connect app.example.com:443 -tls1_1 </dev/null 2>&1 | grep -i 'no protocols\|alert'
openssl s_client -connect app.example.com:443 -tls1_3 </dev/null 2>&1 | grep -i 'Protocol\|Cipher'
Expected result: Legacy TLS is refused while TLS 1.3 negotiates a strong AEAD suite.
How to confirm it worked
Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows the scanner reports no legacy protocol support and modern clients negotiate strong AEAD suites.
Troubleshooting
Legacy clients break — Document the client matrix and provide a separate endpoint only if a compliance reason exists.
Cipher list rejected — Check the terminator syntax; some expect OpenSSL names, others IANA names.
Limitations
- Breaking legacy clients is a compatibility decision.
- Does not cover certificate or key strength.
- Cipher preference interacts with HTTP/2 requirements.