TLS and Nginx

· by

Contents

Transport security is an important topic nowadays. We don't want a man in the middle (MITM) to be able to read our communication with banks, our e-mails, or our medical apps. Hence, we need encryption of our data at the transport layer level.

The Problem of Internet Connections

The internet is a network. It is not connecting your machine with every other one directly, but uses nodes in between. As it is basically connecting everybody, you also have some attackers within the network:

The Internet: Connecting you with Services and Attackers
The Internet: Connecting you with Services and Attackers

The internet is engineered in a way that very often you can imagine the connection between you and a service as a direct one, although it is not direct. That connection is not safe. At the very least you can imagine people reading your traffic (e.g. when you use a wireless connection that's called WLAN Sniffing, the same thing works when you're in the same network). In a worse case they might be able to change your communication. These types of attacks are called Man-in-the-middle attacks:

A Man in the Middle Attack
A Man in the Middle Attack

The Solution: Public-key cryptography

There is a super neat technique called Public-key cryptography. It enables you to generate two keys. We call one of them the public key and the other the private key.

Imagine them as a combination of keys / locks:

  • Stuff that is encrypted (locked) with the private key can only be decrypted (unlocked) with the public key
  • Stuff that is encrypted with the public key can only be decrypted with the private key.

So we make the public key ... well, public. Meaning we share the public key with the world. Whenever somebody wants to send us a message, they can use our public key and only we will be able to read it as long as we keep the private key private.

The Problem of Manipulating MITM

Public-key cryptography is awesome, once we have shared the public key with the world. But we might not even get that far if an attacker manages to intercept our messages. The attacker could share his public key with the world instead. Then, when somebody wants to have a private communication with us, they use the attacker's public key. The attacker decrypts the message with their private key, reads it, re-encrypts it with our public key, and forwards it. We think everything was fine.

The Solution: Certificate Authorities

A Certificate Authority (CA) is a trusted third party. A certificate is a digital document which says "This public key belongs to that domain". It is basically again public-key cryptography, but with a trusted third party. The website owner sends their public key to the certificate authority. The authority makes sure that it was actually sent from the domain. If that is the case, the CA signs the public key with their private key. The public key of the CA is well known (e.g. delivered with the browser at installation).

The Problem: Compromised Certificates

It can happen that an attacker gets temporary access to the web service's server. Then the attacker can copy the private key of the service.

The Solution: OCSP Stapling

The web service has to revoke the certificate. This means it has to tell the CA that the private key was compromised. But how does the client (user) get to know about this?

Three possibilities: CRL, OCSP, and OCSP stapling.

There is a pretty good video about Revocation of digital certificates: CRL, OCSP, OCSP stapling.

Essentially, OCSP stapling means that the server regularly fetches a signed, timestamped OCSP response from the CA and "staples" it to the TLS handshake.

Overview of Certificate Authorities

You can see the Certificate Authority in Chrome by clicking on the lock icon left of the URL:

Checking the Certificate Authority in Chrome
Checking the Certificate Authority in Chrome

Commonly used Certificate Authorities are:

  • Let's Encrypt: Used by BMW, Stack Overflow, ccc.de, kit.edu
  • DigiCert: Used by Reddit, Twitter, Audi, Amazon, mozilla.org, Instagram, live.com, netflix.com, ebay.com, emirates.com, paypal.com, n26.com, deutsche-bank.de
  • GlobalSign: Used by Wikipedia, Baidu.com, qq.com, post.de
  • GeoTrust: nokia.com, tk.de, sixt.com, qantas.com, mit.edu
  • Entrust: comdirect.com
  • Comodo: namecheap.com

There are also some German ones:

  • D-Trust: sparkasse.de, elster.de, bundesdruckerei.de
  • ZIVIT: bund.de
  • Telesec: bundesregierung.de, telekom.de
  • DFN-Verein: tum.de, uni-muenchen.de, uni-heidelberg.de, charite.de, rwth-aachen.de, fernuni-hagen.de

Microsoft and Google have their own CA. It's a bit weird that Microsoft uses DigiCert for live.com.

You might also be interested in features of a CA.

CA Price Founded in Employees
Let's Encrypt Free 2014 13
DigiCert $218 / Year 2003 1000+
GeoTrust $149 / Year 2001
GlobalSign $349 / Year 1996
Entrust $199 / Year 1994 350
Comodo $89 / Year 1998 1200+

I was not happy with the usage numbers. Let's Encrypt claims to have 152 288 000 domains (2018-12-30, source), but w3techs.com says they have a market share of 0.1%. According to them, IdenTrust has a market share of 49.9%, Sectigo of 25.0% and Digicert of 13.6%.

SSL, TLS and HTTPS

Here are super short explanations of what the important terms mean:

SSL (Secure Sockets Layer)
A cryptographic protocol used for network traffic
TLS (Transport Layer Security)
An updated version of SSL.
HTTPS (Hypertext Transfer Protocol Secure)
Using HTTP with transport layer encryption (e.g. SSL or TLS)
Certificate
An electronic document used to prove the ownership of a public key.

Nginx SSL options

You can find options for nginx at cipherli.st, mozilla.github.io as well as in certbot.

Config Miguel Grinberg cipherli.st certbot Explanation
ssl_session_timeout 1d 10m 1d The lower this value, the higher the load on your
  server and the higher the security.
ssl_prefer_server_ciphers on on on tell the client that we have a preferred order of cipher suites
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3 TLSv1 TLSv1.1 TLSv1.2 The higher this value, the more likely there are some devices which don't support it
ssl_ciphers MANY! EECDH + AESGCM:EDH + AESGCM MANY!
ssl_session_cache shared:SSL:50m shared:SSL:10m shared:le_nginx_SSL:1m
ssl_session_tickets off off
ssl_stapling on on OCSP
ssl_stapling_verify on on verification of the OCSP responses received from the CA
HSTS add_header Strict-Transport-Security max-age=15768000; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; Tell the client that we don't like HTTP
add_header X-Frame-Options DENY; make sure it is not embedded in a frame or iframe
add_header X-Content-Type-Options nosniff; See Content sniffing and mozilla.org
add_header X-XSS-Protection "1; mode=block"; mozilla.org, stackoverflow

You might also want to redirect http to https (return 301 https://$host$request_uri;). HSTS is the more secure option, though.

See also