Back to articles
encryption
8 min readJanuary 25, 2026

TLS 1.3: What Actually Changed and Why You Should Care

TLS 1.3 dropped the broken crypto, cut the handshake in half, and made forward secrecy mandatory. Here's a practical upgrade guide for Nginx — and the gotchas nobody mentions.

TLS 1.3: What Actually Changed and Why You Should Care

TLS 1.3: What Actually Changed and Why You Should Care

I ran an SSL Labs scan on a client's server last year and it came back with a B rating. They were serving TLS 1.0 alongside 1.2, with a cipher suite list that looked like it was copied from a 2012 Stack Overflow answer. The thing is, the server was set up in 2021. Someone had just used an old config template and never revisited it.

TLS 1.3 was finalized in 2018, and it represents the most significant security improvement to transport encryption in over a decade. Yet I still encounter servers running TLS 1.2 as their best option, and some still accepting TLS 1.0 connections. Here's why the upgrade matters and how to do it without breaking things.

What TLS 1.3 Actually Fixed

The improvements aren't incremental. TLS 1.3 is a fundamentally cleaner protocol that removed years of accumulated security debt.

What Got Removed (Good Riddance)

  • RSA key exchange — vulnerable to attacks like FREAK and ROBOT, and critically, it doesn't provide forward secrecy. If someone records your encrypted traffic today and steals your private key next year, they can decrypt everything retroactively. TLS 1.3 makes this impossible.
  • MD5 and SHA-1 in handshake signatures — both cryptographically broken
  • RC4, DES, 3DES cipher suites — all known to be weak or broken
  • Export-grade cryptography — a relic from 1990s US crypto export restrictions, absurdly weak by modern standards
  • Static Diffie-Hellman — replaced with ephemeral-only key exchange

What Got Added or Improved

  • 1-RTT handshake instead of 2-RTT in TLS 1.2 — the connection is established in one round trip, which is noticeably faster on high-latency connections
  • 0-RTT resumption for returning visitors — if a client has connected before, it can send data immediately without waiting for the handshake to complete. This is a big deal for perceived performance.
  • Forward secrecy is now mandatory — not optional, not "recommended," mandatory. Every connection uses ephemeral keys.
  • Encrypted handshake — in TLS 1.2, the handshake metadata (including the certificate) is sent in the clear. TLS 1.3 encrypts most of the handshake, which prevents eavesdroppers from fingerprinting your server configuration.

That last point matters more than people realize. Encrypted handshakes make it harder for network middleboxes (corporate firewalls, ISP equipment) to inspect and interfere with your connections. Some organizations have actually pushed back against TLS 1.3 for this exact reason — they want to inspect traffic. That should tell you something about how effective the encryption is.

Enable TLS 1.3 on Nginx

If you're running Nginx 1.13.0+ with OpenSSL 1.1.1+, you already have TLS 1.3 support. Here's a solid production configuration:

nginx
server {
    listen 443 ssl http2;

    ssl_protocols TLSv1.2 TLSv1.3;  # Keep 1.2 for compatibility
    ssl_prefer_server_ciphers off;    # Let clients pick (TLS 1.3 handles this)

    # TLS 1.3 cipher suites are auto-negotiated
    # TLS 1.2 fallback ciphers
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;  # Disable for perfect forward secrecy
}

A few things to note here.

ssl_prefer_server_ciphers off
might seem counterintuitive — shouldn't the server pick the strongest cipher? In TLS 1.3, the cipher suites are all strong by design (the weak ones were removed from the spec entirely), so letting the client choose allows it to pick the cipher its hardware accelerates best. For the TLS 1.2 fallback, the ciphers listed above are all AEAD ciphers with ephemeral key exchange — no CBC, no RSA key exchange.

ssl_session_tickets off
is about forward secrecy. Session tickets reuse key material, which means if the ticket key is compromised, past sessions can be decrypted. If forward secrecy matters to your threat model (and it should for most applications), turn tickets off.

Gotcha: If you're using Let's Encrypt certificates (and you should be — see our Let's Encrypt setup guide), make sure your Certbot is up to date. Older versions might overwrite your hand-tuned TLS config during renewal. Check your renewal hooks and test with

certbot renew --dry-run
after making changes.

Deprecate TLS 1.0 and 1.1

This isn't optional advice anymore. TLS 1.0 and 1.1 have been officially deprecated by the IETF since 2021. Major browsers have dropped support. PCI DSS compliance requires TLS 1.2 minimum. If you're still serving 1.0 or 1.1, you're carrying risk for essentially zero benefit.

nginx
# Remove TLS 1.0 and 1.1 entirely
ssl_protocols TLSv1.2 TLSv1.3;
# NOT: ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

"But what about old clients?" I hear this a lot. Check your access logs. Unless you're serving a government site in a region with very old infrastructure, the percentage of clients that only support TLS 1.0 is effectively zero. Even Android 5.0 (released in 2014) supports TLS 1.2. You're not losing real users by dropping 1.0/1.1 — you're just removing attack surface.

The 0-RTT Caveat

0-RTT resumption is the headline performance feature of TLS 1.3, but it comes with a security trade-off that most guides gloss over: 0-RTT data is vulnerable to replay attacks. An attacker who captures the initial 0-RTT payload can resend it, and the server will process it again.

For idempotent requests (GET), this is usually fine. For anything that changes state (POST, PUT, DELETE), 0-RTT replay is a real problem. Most servers handle this by only allowing 0-RTT for safe HTTP methods, but you should verify your setup actually enforces this.

Test Your Configuration

After changes, test at SSL Labs — aim for an A+ rating with TLS 1.3 as the preferred protocol. Also check Security Headers for the HTTP-level security headers that complement your TLS config.

Don't just test once. I set up a monthly cron job that runs

testssl.sh
against our production domains and sends the results to Slack. TLS configurations can regress during deployments, server migrations, or automated certificate renewals. Continuous testing catches regressions before your customers (or security auditors) do.

The Bottom Line

TLS 1.3 is unambiguously better — faster handshakes, stronger security, simpler configuration. The migration path is straightforward, the compatibility impact is negligible, and the performance benefit from reduced round trips is measurable. If you're reading this and your servers don't have TLS 1.3 enabled, that's your task for today. It's a 5-minute config change that meaningfully improves your security posture.

Discussion

0 comments

Share your thoughts

No comments yet. Be the first to share your thoughts!