Most sites have HTTPS. Far fewer have it configured well. The common faults are old protocol versions still switched on for compatibility nobody needs, weak cipher suites left in the default list, and certificates that expire because renewal depended on someone's calendar.
None of this is exotic, and each item below can be checked from outside. Our free OSINT and domain check tests most of them for your domain, so you can see where you stand before you change anything.
Protocol versions
- Offer TLS 1.2 and TLS 1.3. Make TLS 1.2 the minimum.
- Turn off SSL 3.0, TLS 1.0 and TLS 1.1. SSL 3.0 is broken by the POODLE attack, and RFC 8996 formally deprecated TLS 1.0 and 1.1 in 2021. PCI DSS does not accept them for protecting cardholder data.
- Check every device that terminates TLS for the name: the web server, the load balancer, the CDN and the WAF. The weakest one sets your real posture.
Cipher suites
A configuration for nginx that does this, and is the one this site runs:
- Allow only AEAD suites with ephemeral key exchange: ECDHE with AES-GCM or ChaCha20-Poly1305.
- Remove RC4, 3DES, single DES, export-grade, NULL and anonymous suites. They are weak enough to be exploited, and some provide no encryption at all.
- Remove static-RSA key exchange suites, those named TLS_RSA_WITH_*. They give no forward secrecy: anyone who records traffic now and obtains the key later can read it.
- Leave ssl_prefer_server_ciphers off. When every suite you offer is strong, letting the client choose the one that is fastest on its hardware costs you nothing.
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_session_tickets off;
add_header Strict-Transport-Security "max-age=15768000" always;The certificate
- Use an RSA key of at least 2048 bits, or an ECDSA P-256 key.
- Make sure it is signed with SHA-256 or stronger. SHA-1 certificates have not been trusted by browsers for years.
- List every hostname the site answers on in the certificate's subject alternative names.
- Send the full chain, including intermediates. A missing intermediate works in some browsers and fails in mobile apps and API clients.
- Do not use a self-signed or private-CA certificate on a public site.
- Add a CAA DNS record naming the authorities allowed to issue for your domain.
Renewal
Expired certificates are the most common and most avoidable outage in this list. The CA/Browser Forum has voted to shorten the maximum life of public certificates in stages, so the interval will keep falling.
- Automate renewal, for example with ACME and a client such as Certbot. Do not rely on a calendar reminder.
- Monitor the expiry date from outside, and alert at 30 days and again at 14.
- Test that renewal works before you need it, including the reload of the service that uses the certificate.
Around the handshake
- Redirect HTTP to HTTPS, and send the Strict-Transport-Security header so browsers stop trying HTTP at all. Start with a shorter max-age and lengthen it once you are sure every subdomain works. Think carefully before using preload, because it is hard to undo.
- Check for mixed content: a secure page that loads scripts or images over plain HTTP.
- Turn on OCSP stapling only if your CA still publishes an OCSP responder. Let's Encrypt has stopped, which is why this site does not staple.
- Do the same for email. Publish MTA-STS and TLS-RPT so that mail between servers is encrypted and failures are reported.
How to check it yourself
From a terminal, openssl can test a specific protocol version. A refusal for TLS 1.1 is what you want to see:
openssl s_client -connect example.com:443 -servername example.com -tls1_1
openssl s_client -connect example.com:443 -servername example.com -tls1_2