Securing TLS on Nginx

Ayaz Ahmed Khan
Libel
Published in
3 min readFeb 7, 2020

--

There are several ways you can secure the TLS configuration for any application on Nginx. These include:

  • Offering only strong TLS versions, such as TLS 1.2 and TLS 1.3.
  • Offering only strong cipher suites.
  • Using a server specific DH params key that is unique to that server.
  • Using a strong TLS private key and certificate pair, based on a strong encryption algorithm and a big size for the private key.
  • Optional use of OSCP stapling, HSTS, and public key pinning. We won’t go into the details of these. We will, however, talk about cipher suites and how we can manipulate their configuration on Nginx on a per application basis.

A security-minded customer recently approached us asking to disable a number of weak TLS ciphers. He had run an SSL scan using the SSL Labs test utility. The results from SSL Labs had listed a number of TLS ciphers and marked them as weak. The customer wanted us to remove those.

Let’s take an example of the following TLS cipher that was listed as weak by SSL Labs: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384. This was a TLS 1.2 specific cipher. Ciphers can be different for different TLS versions.

The first problem was that when we ran the command

openssl ciphers -tls1_2

which lists down all supported OpenSSL ciphers, and tried to locate the TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 cipher in the list, we did not find anything. This misled us to believe that this particular cipher was not supported. It was also confusing because SSL labs was showing that it was enabled on the server.

The first thing to understand about the “openssl ciphers -tls1_2” command is that it will list all supported OpenSSL ciphers. This does not mean that all of these are also enabled on Nginx for a particular application. It only means that these ciphers are supported by the OpenSSL library/toolset installed on the server.

The second important thing to understand is that there are different naming conventions for TLS ciphers. OpenSSL uses its own naming convention, while SSL labs uses the IANA naming convention. This is where the confusion creeps in from. The TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 cipher exists in the IANA naming convention only. Since SSL labs uses the IANA format, we only ever see ciphers in IANA naming conventions. However, OpenSSL does not use the IANA convention (at least not anymore). It uses its on OpenSSL naming convention.

In other words, the TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 cipher in IANA naming convention is actually ECDHE-RSA-AES256-SHA384 in OpenSSL naming convention. So:

IANA: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384

OpenSSL: ECDHE-RSA-AES256-SHA384

If we are looking for ciphers in the IANA naming convention in the output of OpenSSL, it is no surprise that we are going to find nothing. You can look at this page to see which IANA ciphers are mapped to which OpenSSL ones.

First things first, we have to convert the IANA style ciphers into the OpenSSL ciphers before we can start disabling them.

While SSL labs is really good at what it does, there’s another open source utility that we can set up on a Linux system to run SSL scans. It’s called “sslscan“. It’s very easy to use. We can also use the openssl command on a Linux system to check whether a particular cipher is enabled on the server or not:

openssl s_client -connect IP:PORT -cipher CIPHER_NAME -tls1_2

If the cipher is enabled, you will receive the full SSL handshake and the full SSL certificate dump.

Now comes the part about disabling it. This has to be done at the Nginx level. In the SSL configuration block on Nginx, the ssl_ciphers parameter contains supported ciphers. It will help to look at the format this parameter supports, because it supports direct, full fledged ciphers, cipher combinations, as well as ciphers that should be explicitly disabled. The easiest way to disable this given cipher is to add it at the end of the line preceded by the exclamation sign (!, the not character for negation): !ECDHE-RSA-AES256-SHA384

After reloading Nginx, we can verify whether this works by running the openssl command above, the sslscan utility, or re-running the SSL labs test.

Not so bad, is it?

I wrote this internally for work but thought that the wider community could benefit from it.

--

--