SSL/TLS Best Practices
Transport Layer Security (TLS) is the cryptographic protocol that secures virtually all communication on the internet. When you see the padlock icon in your browser's address bar, TLS is what makes that connection private and authenticated. Despite being a mature technology, TLS misconfiguration remains one of the most common security issues on the web. Expired certificates, outdated protocol versions, weak cipher suites, and missing HSTS headers continue to affect millions of websites. This lesson covers everything you need to know to configure TLS correctly and keep it that way.
TLS 1.3 vs TLS 1.2
TLS 1.3, finalized in 2018 (RFC 8446), is the current standard and a significant improvement over TLS 1.2. While TLS 1.2 remains acceptable for backward compatibility, TLS 1.3 should be your primary target.
Key improvements in TLS 1.3
- Faster handshake: TLS 1.3 completes the handshake in one round trip (1-RTT) compared to two round trips (2-RTT) for TLS 1.2. This reduces latency for every new connection. TLS 1.3 also supports a 0-RTT mode for resumed connections, though 0-RTT has replay attack considerations.
- Removed insecure features: TLS 1.3 eliminates support for older, vulnerable cipher suites and algorithms. RSA key exchange, CBC mode ciphers, RC4, SHA-1, MD5, and compression are all removed. This makes misconfiguration harder because there are fewer options and all of them are secure.
- Forward secrecy by default: Every TLS 1.3 cipher suite uses ephemeral Diffie-Hellman key exchange, ensuring forward secrecy. Even if the server's private key is compromised in the future, past traffic cannot be decrypted. TLS 1.2 supports forward secrecy but does not require it.
- Encrypted handshake: In TLS 1.3, the server certificate and most handshake messages are encrypted, providing better privacy. In TLS 1.2, the certificate is sent in plaintext, allowing passive observers to see which site a user is connecting to.
- Simpler protocol: TLS 1.3 has a cleaner, simpler specification with fewer options, reducing the attack surface and making implementations less error-prone.
Protocol version support
- TLS 1.3: Supported by all modern browsers. Use it as your primary protocol.
- TLS 1.2: Still acceptable and needed for older clients. Ensure you use only strong cipher suites.
- TLS 1.1 and TLS 1.0: Deprecated by all major browsers and RFC 8996. Disable them immediately.
- SSL 2.0 and SSL 3.0: Severely broken protocols. Must be disabled. If they are enabled, your server has a critical security vulnerability.
Certificate management
TLS certificates (often called SSL certificates for historical reasons) authenticate your server to the client. Proper certificate management is essential — an expired or misconfigured certificate can lock users out of your site or expose them to man-in-the-middle attacks.
Let's Encrypt
Let's Encrypt is a free, automated, open certificate authority run by the Internet Security Research Group (ISRG). It has fundamentally changed the certificate landscape by making TLS certificates available to everyone at no cost with fully automated issuance and renewal.
Key features
- Free: No cost for certificates, removing the financial barrier to HTTPS.
- Automated: Certificates can be issued and renewed entirely through the ACME protocol without human intervention.
- Short-lived: Certificates are valid for 90 days, encouraging automated renewal and limiting the window of exposure from a compromised key.
- Widely trusted: Let's Encrypt certificates are trusted by all major browsers and operating systems.
Certbot example
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain and install a certificate for Nginx
sudo certbot --nginx -d example.com -d www.example.com
# Set up automatic renewal (usually auto-configured)
sudo certbot renew --dry-run
# Cron job for renewal (runs twice daily)
0 0,12 * * * certbot renew --quiet
Automated renewal
Certificate expiration is one of the most common causes of site outages. Automated renewal eliminates this risk entirely. Certbot configures a systemd timer or cron job that checks daily whether renewal is needed. Other ACME clients like acme.sh, Caddy (built-in), and cloud provider services (AWS Certificate Manager, Cloudflare) also handle renewal automatically.
certbot renew --dry-run to verify that automated renewal works. Monitor certificate expiration dates with tools like SSL Labs, UptimeRobot, or CodeFrog — do not rely solely on automation.
HSTS preloading
HTTP Strict Transport Security (HSTS), covered in the Security Headers lesson, tells browsers to only connect to your site over HTTPS. HSTS preloading takes this one step further by building your domain into browsers' HSTS preload lists so that HTTPS is enforced from the very first visit — before any HTTP request is ever made.
Requirements for preloading
- Serve a valid HTTPS certificate.
- Redirect all HTTP traffic to HTTPS on the same host.
- Serve the HSTS header with:
max-ageof at least 31536000 (one year),includeSubDomains, andpreload. - All subdomains must also support HTTPS.
Submitting for preloading
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Once your header meets the requirements, submit your domain at hstspreload.org. Browsers (Chrome, Firefox, Safari, Edge) will include your domain in their built-in preload list, which ships with browser updates.
Cipher suites
Cipher suites define the combination of algorithms used for key exchange, authentication, bulk encryption, and message authentication during a TLS connection. Choosing the right cipher suites is critical for both security and compatibility.
TLS 1.3 cipher suites
TLS 1.3 only supports five cipher suites, all of which are strong:
TLS_AES_256_GCM_SHA384(recommended)TLS_AES_128_GCM_SHA256(recommended)TLS_CHACHA20_POLY1305_SHA256(recommended, especially for mobile devices)TLS_AES_128_CCM_SHA256TLS_AES_128_CCM_8_SHA256
You cannot misconfigure TLS 1.3 cipher suites because there are no weak options.
TLS 1.2 cipher suites to prefer
For TLS 1.2 backward compatibility, use only cipher suites with forward secrecy (ECDHE key exchange) and AEAD encryption (GCM or CHACHA20):
# Nginx configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
Cipher suites to avoid
- Anything with
RC4— broken cipher, completely insecure. - Anything with
3DES— vulnerable to Sweet32 attack, slow. - Anything with
CBCmode — vulnerable to padding oracle attacks (POODLE, Lucky13). - Anything with
RSAkey exchange (without ECDHE) — no forward secrecy. - Anything with
NULL— no encryption at all. - Anything with
EXPORT— deliberately weakened ciphers from the 1990s (FREAK, Logjam attacks).
Certificate Transparency
Certificate Transparency (CT) is a system for publicly logging all issued TLS certificates. It allows anyone to monitor which certificates have been issued for their domains, detecting misissued or fraudulent certificates quickly.
How it works
- Certificate authorities (CAs) submit all issued certificates to public CT logs.
- Browsers require certificates to include Signed Certificate Timestamps (SCTs) proving they have been logged.
- Domain owners and security researchers can monitor CT logs for unexpected certificates.
Why it matters
- Detects unauthorized certificates issued by compromised or rogue CAs.
- Provides accountability for certificate authorities.
- Enables domain owners to detect phishing sites using fraudulent certificates for their domains.
- All major browsers now require CT for new certificates.
Monitoring tools
- crt.sh — Free certificate search tool that queries CT logs.
- Facebook CT Monitoring — Email alerts when certificates are issued for your domains.
- SSLMate Cert Spotter — Free CT log monitoring service.
Tools for testing
SSL Labs Server Test
Qualys SSL Labs provides the most comprehensive and widely used free TLS scanner. It grades your server's TLS configuration from A+ to F, testing protocol versions, cipher suites, certificate chain, key exchange parameters, and known vulnerabilities. An A+ grade requires HSTS.
# Test your server (web interface)
https://www.ssllabs.com/ssltest/analyze.html?d=yourdomain.com
testssl.sh
testssl.sh is an open-source command-line tool that tests a server's TLS configuration locally, without sending data to a third-party service. It is useful for testing internal servers, staging environments, or when you need to automate TLS testing in CI/CD pipelines.
# Install
git clone https://github.com/drwetter/testssl.sh.git
# Run a full test
./testssl.sh yourdomain.com
# Test specific aspects
./testssl.sh --protocols yourdomain.com
./testssl.sh --ciphers yourdomain.com
./testssl.sh --vulnerable yourdomain.com
Common mistakes
Mixed content
Mixed content occurs when an HTTPS page loads resources (scripts, images, stylesheets) over HTTP. This undermines the security of the entire page because an attacker can intercept and modify the HTTP resources. Browsers block mixed active content (scripts) entirely and may warn about or block mixed passive content (images).
- Use protocol-relative URLs (
//example.com/image.png) or always usehttps://for external resources. - Set the CSP directive
upgrade-insecure-requeststo automatically upgrade HTTP requests to HTTPS. - Audit your pages for mixed content using browser developer tools or CodeFrog's scanning.
Expired certificates
An expired certificate triggers a full-page browser warning that most users will not click through. This effectively takes your site offline. Automated renewal with Let's Encrypt/Certbot and monitoring with tools like SSL Labs or UptimeRobot prevents this.
Weak cipher suites
Enabling outdated cipher suites for "backward compatibility" can weaken your security. Downgrade attacks (like POODLE) exploit the ability to negotiate weak ciphers. Only enable cipher suites that use AEAD encryption (GCM, CHACHA20) and forward secrecy (ECDHE).
Incomplete certificate chains
Your server must send the complete certificate chain — your certificate plus all intermediate certificates — but not the root certificate. Missing intermediate certificates cause validation failures on some clients (often Android devices or certain curl versions) even though browsers with cached intermediates may work fine.
Self-signed certificates in production
Self-signed certificates should never be used in production. They train users to click through security warnings, and they cannot be verified by clients without manual trust store configuration. With Let's Encrypt providing free certificates, there is no reason to use self-signed certificates in production.
Not redirecting HTTP to HTTPS
Having a valid TLS certificate is not enough if users can still access your site over HTTP. Always configure a 301 redirect from HTTP to HTTPS, and deploy HSTS to ensure future visits go directly to HTTPS.
# Nginx HTTP to HTTPS redirect
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Resources
- SSL Labs Server Test — Free comprehensive TLS scanner (A+ is the target grade)
- testssl.sh — Open-source command-line TLS testing tool
- Let's Encrypt — Free automated certificate authority
- HSTS Preload List — Submit your domain for browser preloading
- Mozilla SSL Configuration Generator — Generate secure TLS configurations for Apache, Nginx, HAProxy, and more
- crt.sh — Certificate Transparency log search