And ditch insecure and weak TLS ciphers or risk attack

SSL, or TLS as it should be called these days, is THE de rigueur of modern web site hosting. Well, not so much de rigueur, but more of a necessity. It’s not just about security (encryption between your web browser and the webserver), but SEO (search engine optimisation) requires an SSL/TLS certificate as search engines such as Google are prioritising SSL/TLS protected sites above non-secure sites (see http://www.bafta.org, an example of a web site which could – and indeed should – be using an encryption connection throughout, but doesn’t).

And it’s not just all about encryption. With the HTTP/2 protocol – assuming your web server supports it – can provide a number of improvements that can significantly boost the performance of your site as well.

SSL/TLS certificates used to cost a fortune and were difficult to manage. Every year or so, you’d have to create a new certificate signing request (and private key, if necessary) and then submit the CSR to an SSL vendor. You’d then have to verify you own the domain either by placing a text file on your website, or an entry in DNS. And you’d be paying a pretty penny in the process. And that’s just to protect one URL (or, in the case of most SSL vendors – actually two – one for a subdomain (such as ‘www’), and the other for the bare domain (such as ‘drake.org.uk’). If you wanted to protect a whole bunch of subdomains, you could buy a wildcard SSL certificate. These are even more expensive (though the cheapest I found was $45 per year), but can be deployed across multiple servers and hostnames under the same domain.

Then came along Let’s Encrypt. It’s a free certificate authority that issues free single hostname and wildcard SSL certificates. It’s easily automated and requires very little effort. Wildcard SSL certificates are relatively new – and most people end up issuing single domain certificates through the “certbot” utility.

But it’s just as easy to get a wildcard cert which can be renewed automatically. Usually, like me, you’d run certbot with the –nginx command which sorts out your nginx configuration for you. But if you wanted a wildcard certificate instead, it requires a bit extra work:

certbot-auto certonly --manual --preferred-challenges=dns \
--email [email protected] \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos -d *.wombats-are-cool.com

You’ll then be prompted by certbot to add a DNS entry to your domain (in this example, wombats-are-cool.com) and then it’ll go off and verify it exists and issue the certificate. Keep your DNS TTL record for a quick resolution.

Once issued, you’d just alter your nginx server block with:

ssl_certificate /etc/letsencrypt/live/wombats-are-cool.com/fullchain.pem; # managed by Certbot

ssl_certificate_key /etc/letsencrypt/live/wombats-are-cool.com/privkey.pem; # managed by Certbot

Then shove the following in /etc/crontab:

0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/bin/certbot-auto renew

(add > /dev/null 2>&1 to taste)

A free wildcard SSL certificate which will automatically renew itself. An alternative to Let’s Encrypt is to use a WAF or CDN such as Cloudflare or Sucuri – both will offer to install a certificate at the edge (e.g. their servers – all traffic will go through their datacentres before being passed to your origin server). This requires a bit more set-up, especially if you want to the WAF/CDN to connect over HTTPS to the origin server. There are a number of approaches to this – including, ironically, using Let’s Encrypt.

Now, don’t forget to disable SSLv3, TLS v1.0 and v1.1 and use strong ciphers. Don’t do what many web site owners do, and accept any old nonsense.

In the following example (from a well known UK multi-media facility), the highlighted protocols are terribly insecure and will fail you in any vulnerability scan, and a temptation for intruders and automated bots. TLS v1.1 isn’t worth keeping around – I’ve been looking at the stats of a very high volume e-commerce web site shows that barely anybody uses it. I’ve configured many web sites to use TLS v1.2 at a minimum and it has had absolutely no impact on browser compatibility.

PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers:
|
SSLv3:
| ciphers:
| TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (dh 2048) - C
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_RC4_128_SHA (secp256r1) - C
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| compressors:
| NULL
| cipher preference: client
| warnings:
| 64-bit block cipher 3DES vulnerable to SWEET32 attack
| Broken cipher RC4 is deprecated by RFC 7465
| CBC-mode cipher in SSLv3 (CVE-2014-3566)
|
TLSv1.0:
| ciphers:
| TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (dh 2048) - C
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_RC4_128_SHA (secp256r1) - C
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| compressors:
| NULL
| cipher preference: client
| warnings:
| 64-bit block cipher 3DES vulnerable to SWEET32 attack
| Broken cipher RC4 is deprecated by RFC 7465
|
TLSv1.1:
| ciphers:
| TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (dh 2048) - C
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_RC4_128_SHA (secp256r1) - C
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| compressors:
| NULL
| cipher preference: client
| warnings:
| 64-bit block cipher 3DES vulnerable to SWEET32 attack
| Broken cipher RC4 is deprecated by RFC 7465
| TLSv1.2:
| ciphers:
| TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (dh 2048) - C
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A
| TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
| TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
| TLS_ECDHE_RSA_WITH_RC4_128_SHA (secp256r1) - C
| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
| compressors:
| NULL
| cipher preference: client
| warnings:
| 64-bit block cipher 3DES vulnerable to SWEET32 attack
| Broken cipher RC4 is deprecated by RFC 7465
|_ least strength: C

Or a more visual representation of the above:

Exposing the versions of your server’s web server, OpenSSL and PHP is also a Bad Thing(tm). Which of course, our poor saps absolutely do:

Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.6.30

Don’t do what these people do. Pay attention to your SSL/TLS settings as well as your certificate.

Meanwhile, I’m happy with this: