(KEEPSITESAFE)

Guide

TLS hardening: what each fix actually costs you in visitors

Every TLS scanner hands you a list of things to switch off, and none of them tells you which clients you lose when you do — so here is the bill for each one.

By KeepSiteSafe ·

Three things matter, and everything after that is subtraction

A TLS configuration in 2026 has to get three things right. Protocol floor: TLS 1.2 and 1.3, nothing below. Cipher family: AEAD only, meaning AES-GCM and ChaCha20-Poly1305, which encrypt and authenticate in one pass and so have no separate MAC-and-padding step to leak timing. Key exchange: ECDHE, so that a private key stolen next year does not decrypt the traffic someone recorded today.

If your server does those three, the security-relevant work is finished. Everything a scanner tells you afterwards is subtraction — turning off things you additionally offer — and subtraction is where the cost lives. No scanner prices it for you.

"At the cost of old clients" is a shrug, not advice

The output of every TLS scanner is a list of things to disable, and the compatibility warning is always the same vague sentence. Which clients? How old? Are they your clients? That question has an answer, and it is different for each finding, so the rest of this article works through them one at a time.

There is a second question worth separating out. A CVSS score is a model of how bad a flaw would be if someone exploited it. The CISA KEV catalogue — roughly 1,650 entries, public domain, each with a federal remediation due date — is a record of what attackers are actually exploiting. Those are not the same question, and the second one should drive your ordering. Nothing in this article about ciphers appears in KEV. Your out-of-date CMS plugin might.

TLS 1.0 and 1.1

Remove them. This is the one finding where the cost really is nil. Chrome, Firefox, Safari and Edge all dropped TLS 1.0 and 1.1 in 2020, so no current browser will ever negotiate them, and no browser user can be affected by the removal. PCI DSS has required TLS 1.0 to be off since mid-2018, so if you take card payments this is not optional. Most graders cap your score for offering them.

Who you actually lose: Windows XP with IE8, Android 4.4 and earlier, unpatched Java 6 and 7, and a long tail of payment terminals, printers and building-management boxes. If one of those is a real client of yours, you know it already, and the answer is to fix that client rather than hold the whole site back.

CBC ciphers and LUCKY13

This is the finding that consumes the most attention and deserves the least. Be clear about what it is. LUCKY13 (CVE-2013-0169) is a timing side channel in the MAC-then-encrypt construction TLS 1.2 uses with CBC ciphers: the time taken to check padding varies very slightly with the plaintext. To exploit it, an attacker needs a man-in-the-middle position on the network path, the ability to make the victim's client repeat the same secret in the same position across an enormous number of requests, and timing measurements clean enough to see sub-microsecond differences. It has never been demonstrated as a practical attack over the internet. OpenSSL, BoringSSL and NSS have shipped constant-time countermeasures for over a decade. TLS 1.3 removed CBC entirely, which is why it keeps surfacing as a modernity complaint dressed up as a vulnerability.

The cost of removing CBC comes in two very different sizes, and scanners blur them.

The cheap version is dropping CBC from your TLS 1.2 cipher list while keeping TLS 1.2 itself. TLS 1.2 supports AES-GCM and ChaCha20-Poly1305 perfectly well, so an AEAD-only 1.2 list satisfies the finding. You lose clients whose only overlap with you was a CBC suite: Android 5 and 6 era stacks, Java 7, anything on OpenSSL 0.9.8 or 1.0.1. Usually acceptable.

The expensive version is what grade-chasing pushes you towards — TLS 1.3 only, so CBC cannot be negotiated at all. That bill is much larger:

  • Chrome before 70 and Firefox before 63. The commonly quoted "Firefox 55" is misleading: 55 through 62 spoke only draft versions of TLS 1.3, which a modern server will not accept, so treat anything under 63 as excluded.
  • Anything on Windows 10 using Schannel. Windows 10's TLS stack never supported TLS 1.3 and never will. Browsers on Windows 10 are unaffected because Chrome and Firefox ship their own TLS libraries, which is exactly why this gets missed in testing — you check in a browser, it works, and meanwhile every .NET Framework HttpClient, every PowerShell 5.1 Invoke-WebRequest, and a pile of enterprise software calling WinHTTP simply cannot connect. Windows 10 left mainstream support in October 2025, but ESU and the LTSC channels keep those machines in service for years yet.
  • OpenSSL 1.0.2, which means CentOS 7, RHEL 7 and Ubuntu 16.04. TLS 1.3 needs 1.1.1 or newer. Any script or agent on those boxes stops working.
  • Android 9 and earlier, where TLS 1.3 was not on by default.
  • Java 10 and earlier — and Java 8 before update 261, since Oracle backported TLS 1.3 there. "Java 8 doesn't do TLS 1.3" is now wrong more often than it is right.
  • TLS-inspecting corporate proxies, which lag worst of all and will fail closed for an entire office with no useful error message.

So: strip CBC from TLS 1.2 if you like, it is close to free. Going 1.3-only to make a scanner stop complaining about a 2013 timing paper is not a trade most sites should take.

3DES, SWEET32 and RC4

Both genuinely free to remove. SWEET32 exploits 3DES's 64-bit block size, which makes block collisions probable after about 32 GB on a single connection, while the paper's actual working attack needed roughly 785 GB over some 38 hours — impractical, but 3DES buys you nothing anyway. RC4 is properly broken. The only clients that need either are IE8 on XP and Windows Server 2003. Delete them and move on.

Weak Diffie-Hellman and Logjam

The fix is to prefer ECDHE and not offer DHE at all, which is what the config below does. If some client genuinely requires DHE, never rely on your distribution's shipped group — generate your own 2048-bit parameters with openssl dhparam -out /etc/ssl/dhparam.pem 2048 and point ssl_dhparam at it. Under TLS 1.3 the groups are fixed by the protocol and the dhparam file is ignored entirely, so the advice to generate 4096-bit parameters "for safety" now mostly buys you a slower handshake and nothing else. The same goes for jumping your RSA key from 2048 to 4096 bits: measurable CPU cost, no measurable security gain.

The configuration

nginx

# put this in the http block, not a server block — see the note below
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;

# TLS 1.3 suites are not configurable through ssl_ciphers. nginx uses
# OpenSSL's defaults there (AES-GCM and ChaCha20-Poly1305). Leave them.

Two gotchas. First, ssl_protocols and ssl_ciphers are applied per listening socket, taken from the default server for that socket — setting them in one name-based vhost and not the others silently does nothing. Put them in http and override only deliberately. Second, ssl_prefer_server_ciphers off is correct now, and the old advice to turn it on is outdated: client preference is what lets a phone without AES hardware acceleration pick ChaCha20-Poly1305, which is both faster and safer on that device.

Apache

# Apache 2.4.36 or newer, OpenSSL 1.1.1 or 3.x
SSLProtocol -all +TLSv1.2 +TLSv1.3
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
SSLHonorCipherOrder off
SSLOpenSSLConfCmd Curves X25519:prime256v1:secp384r1
SSLSessionTickets off

On Apache older than 2.4.36, +TLSv1.3 is a fatal configuration error and the server refuses to start rather than warning. And a vhost that sets SSLProtocol replaces the inherited value rather than merging with it, so one forgotten vhost carrying a stale SSLProtocol all -SSLv3 quietly re-enables TLS 1.0 for that hostname alone.

Verify from outside, not from the config file

openssl s_client -connect example.com:443 -tls1_2 -cipher 'ECDHE-RSA-AES128-SHA' </dev/null
# want: "no cipher match" or a handshake failure — that means CBC is gone

openssl s_client -connect example.com:443 -tls1_1 </dev/null
# want: the same

If you are behind Cloudflare or any CDN

The handshake your visitors make terminates at the edge, not at your server. Editing nginx changes nothing a scanner sees. Set the floor in the dashboard under SSL/TLS, Edge Certificates, Minimum TLS Version. Your origin config still matters for the edge-to-origin leg and for anyone who finds your origin IP and connects to it directly — worth checking, because a hardened edge in front of a TLS 1.0 origin is a common and completely invisible mismatch.

The honest position

Hardening TLS is worth doing. It takes twenty minutes, it breaks nothing as long as you stay on TLS 1.2 plus 1.3 with AEAD suites, and PCI DSS obliges part of it anyway. But priority is the whole game. A CBC finding on a site behind a modern CDN, running current OpenSSL, already offering TLS 1.3, is close to noise — a decade-old side channel with countermeasures everywhere and no evidence of real-world use. A scanner that paints that red and knocks a letter off your grade is spending your attention on the wrong thing while an exploited CVE in a dependency sits three screens further down.

That is why KeepSiteSafe separates the two. CryptoLyzer inspects the TLS configuration passively on any domain, testssl.sh runs a deeper handshake matrix on domains you have verified you own, and findings are cross-referenced against CISA KEV so "confirmed exploited" is never shown at the same weight as "theoretically weak". It will not find everything, and it is not a substitute for a penetration test. It will tell you which of these findings deserves your Tuesday.

Every check described here is one KeepSiteSafe actually runs, using named open-source engines — Mozilla’s HTTP Observatory, CryptoLyzer and the CISA KEV catalogue. You can verify any finding against its source rather than taking our word for it.

Check your own site

Free scan, no signup, any domain — with the exact fix for every finding, and what applying it will cost you.

Scan free
TLS Hardening: What Each Fix Costs You in Lost Visitors | KeepSiteSafe