Skip to content

Instantly share code, notes, and snippets.

@mapmeld
Last active July 25, 2023 18:55
Show Gist options
  • Save mapmeld/a9bcac46d1f486f81664814a799e5897 to your computer and use it in GitHub Desktop.
Save mapmeld/a9bcac46d1f486f81664814a799e5897 to your computer and use it in GitHub Desktop.
OverEncrypt - paranoid HTTPS

OverEncrypt

This is a guide that I wrote to improve the default security of my website https://fortran.io , which has a certificate from LetsEncrypt. I'm choosing to improve HTTPS security and transparency without consideration for legacy browser support.

WARNING: if you mess up settings, lose your certificates, or decide to no longer maintain HTTPS certs, these steps can and will make your domain inaccessible.

I would recommend these steps only if you have a specific need for information security, privacy, and trust with your users, and/or maintain a separate secure.example.com domain which won't mess up your main site. If you've been thinking about hosting a site on Tor, then this might be a good option, too.

The best resources that I've found for explaining these steps are https://https.cio.gov , https://certificate-transparency.org , and https://twitter.com/konklone

As I research and document this process, I'm starting a Python CLI OverEncrypt to perform these steps or check them automatically.

0. Before starting

Verify that your site with a LetsEncrypt certificate is accessible at https://example.com (for your domain).

You should be running the latest Apache or Nginx, and know the path to your fullchain.pem file.

If you got your first cert several months ago (even early 2016) you might want to check if your site is rated A+ or B on https://www.ssllabs.com/ssltest/index.html

If it's not renewal time, read through these steps, run ./letsencrypt-auto revoke --cert-path /path/to/cert, and do a git pull to update the LetsEncrypt / Certbot client. Then create a new cert in the same location.

1. OCSP Stapling / Must-Staple

LetsEncrypt recently added OCSP Stapling support to have browsers check for certificate revocations, but it does not require it with Must-Staple by default.

When you create a cert with ./letsencrypt-auto, add the option --must-staple to enforce OCSP checks on the certificate level and not just as a header. I'm not sure if it works on renewal.

SSLMate has directions on https://sslmate.com/blog/post/ocsp_stapling_in_apache_and_nginx to configure Nginx or Apache to support OCSP. Most of the headers will be added already by letsencrypt-auto. After you add the remaining ones, make sure to run sudo service apache restart or sudo service nginx restart

2. Public Key Pinning (HPKP)

You need to get SHA256 fingerprints of at least two certificates: your public cert key (which currently changes whenever you renew with LetsEncrypt) and the LetsEncrypt cert used to sign certificates (the cert which I listed here previously does not appear in new LetsEncrypt cert chains ... I will research the correct cert).

This can really mess things up if you switch away from LetsEncrypt or they change their cert, so look at these two first: https://community.letsencrypt.org/t/hpkp-best-practices-if-you-choose-to-implement/4625 and https://news.ycombinator.com/item?id=13074651 to see about adding others, or skipping this step if you're worried about locking people out.

openssl x509 -noout -in /path/to/cert.pem -pubkey | openssl asn1parse -noout -inform pem -out public.key
openssl dgst -sha256 -binary public.key | openssl enc -base64
> aaaa111example

In your Nginx settings

add_header Public-Key-Pins 'pin-sha256="aaaa1111example"; pin-sha256="exampleRootCert"; max-age=2592000; includeSubDomains';

Settings for Apache and many other systems: https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html

3. Certificate Transparency

You can find LetsEncrypt's registered certificates for your site at https://crt.sh/

As best I can tell from https://certificate-transparency.org , this is as much as you need to do for now. Browsers will get smarter about this in the future.

4. Allow Preload

In the part of the cert where it reads add_header Strict-Transport-Security, add 'preload' to the end of the header, e.g. in Nginx add_header Strict-Transport-Security 'max-age=15768000; includeSubDomains; preload'

5. Prefer AES-256 to AES-128

(see @bwesterb comment below... this makes it harder to decrypt your traffic, but TLS key exchange is still a weak point)

This is a personal preference, but makes traffic more resistant to being broken by quantum computers, now or in a collect-now-read-everything-later dystopian future. AES-256 on a quantum computer remains as strong as AES-128 today on classical computers; AES-128 will be (or perhaps is?) broken. You can read more in my write-up of post-quantum encryption.

In the ssl_ciphers section, there is a list of ciphers in order by the server's preferred use, separated by :s. Also some are forbidden. I removed all mentions of AES128 from this list. The generic :AES: allows AES-128 queries unless it's removed, too.

In the future these steps might support Google's work on post-quantum encryption with BoringSSL / Ring Learning With Errors / A New Hope / Lattice-Based Encryption. But not yet. (this would fix the key exchange problem mentioned by @bwesterb)

Retesting

Make sure you've run sudo service apache restart or sudo service nginx restart to use your new cert.

On the top of the SSL Labs test, click the 'Clear Cache' link to re-run tests.

@AyumuKasuga
Copy link

Also if you have preload header you can add your domain to chrome HSTS preload list here.

@AyumuKasuga
Copy link

I think for nginx you can use reload command for gracefully reload :)

@philcryer
Copy link

Nice work, I'll take a look compare with what I have in my project, nginx-globals, which deals with SSL, and other nginx settings to make things better/more secure.

@technion
Copy link

technion commented Dec 1, 2016

 You can find LetsEncrypt's registered certificates for your site at https://crt.sh/

Obligatory note: I run a proactive monitor and alerting service: https://ctadvisor.lolware.net/

@TheGroundZero
Copy link

TheGroundZero commented Dec 1, 2016

Doesn't HPKP require one of the fingerprinted certificates not yet to be provided by your host? I.e. the fingerprint of your current cert and that of a CSR*. Also, if you add the LetsEcnrypt root CA, the browser will trust any certificate signed by that root CA to be trusted for your site.

*Sadly enough LetsEncrypt doesn't have a system that works with auto-renewal and CSR's yet. So you'll have to manually create a new cert with the CSR, remove the old cert's fingerprint from the HPKP header, create a new CSR and add it's fingerprint to the HPKP header.

@mapmeld
Copy link
Author

mapmeld commented Dec 2, 2016

@TheGroundZero I felt that allowing any LetsEncrypt cert was easier, or at least easier to explain, than dual certs that carry over in the max-age time. Allowing any LetsEncrypt cert is still adding a protection, by limiting it to one cert authority. If someone compromises LetsEncrypt or forces them to create a cert, that is big news and I don't know that I can defend against that.

@bwesterb
Copy link

bwesterb commented Dec 6, 2016

Replacing AES-128 with AES-256 won't secure TLS against a quantum computer. The weakest link is the key-exchange: if you can break that, then you don't need to break the symmetric cipher. Practically all key exchange algorithms are way easier to break on decently sized quantum computer, then it is to break AES-128. You need a post quantum keyexchange in your TLS like for instance New Hope. (Or well, we hope New Hope is post quantum secure: no one has figured out yet if it's easier to break on a quantum computer.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment