This is a text-only version of the following page on https://raymii.org:
---
Title       :   Strong SSL Security on nginx
Author      :   Remy van Elst
Date        :   14-06-2015
Last update :   27-04-2019
URL         :   https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
Format      :   Markdown/HTML
---



[![A on ssl labs test][1]][2]

This tutorial shows you how to set up strong SSL security on the nginx
webserver. We do this by updating OpenSSL to the latest version to mitigate
attacks like Heartbleed, disabling SSL Compression and EXPORT ciphers to
mitigate attacks like FREAK, CRIME and LogJAM, disabling SSLv3 and below because
of vulnerabilities in the protocol and we will set up a strong ciphersuite that
enables Forward Secrecy when possible. We also enable HSTS and HPKP. This way we
have a strong and future proof ssl configuration and we get an A+ on the Qually
Labs SSL Test.

I've written an Open Source [SSL server test][3]. You can use it to test your
configuration, as an addition to the other SSL tests our there. It is fast,
shows you all the information so you can make your own informed decision (no
ratings), and the results are saved so you can compare different settings. You
can test your site via <https://ssldecoder.org>.

I've also written a handy tool which notifies you when your certificates are
about to expire. It is open source so you can host it yourself internally and
there is a hosted version available at <https://certificatemonitor.org>.

I've created a website with [Copy-pastable strong cipherssuites for NGINX,
Apache, Lighttpd and other software: https://cipherli.st][4]. Handy if you don't
want to read this entire tutorial. This tutorial and [https://cipherli.st][4]
are updated continuously as new vulnerabilities are discovered.

<p class="ad"> <b>Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:</b><br><br> <a href="https://leafnode.nl">I'm developing an open source monitoring app called  Leaf Node Monitoring, for windows, linux & android. Go check it out!</a><br><br> <a href="https://github.com/sponsors/RaymiiOrg/">Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.</a><br><br> <a href="https://www.digitalocean.com/?refcode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days. </a><br><br> </p>


This tutorial works with the stricter requirements of the SSL Labs test [announced on the 21st of January 2014][6] (It already did before that, if you follow(ed) it you get an A+)

 * [This tutorial is also available for Apache][7]
 * [This tutorial is also available for Lighttpd][8]
 * [This tutorial is also available for FreeBSD, NetBSD and OpenBSD over at the BSD Now podcast][9]

You can find more info on the topics by following the links below:

 * [BEAST Attack][10]
 * [CRIME Attack][11]
 * [Heartbleed][12]
 * [FREAK Attack][13]
 * [Perfect Forward Secrecy][27]
 * [Dealing with RC4 and BEAST][28]

We are going to edit the nginx settings in the file `/etc/nginx/sites-
enabled/yoursite.com` (On Ubuntu/Debian) or in `/etc/nginx/conf.d/nginx.conf`
(On RHEL/CentOS).

For the entire tutorial, you need to edit the parts between the `server` block
for the server config for port 443 (ssl config). At the end of the tutorial you
can find the complete config example.

_Make sure you back up the files before editing them!_

### SSL Protocols

All protocols other than TLS 1.2 and TLS 1.3 are considered unsafe.

Edit the config file:



   ssl_protocols TLSv1.2 TLSv1.3; # Requires nginx >= 1.13.0 else use TLSv1.2


### The Cipher Suite

Forward Secrecy ensures the integrity of a session key in the event that a long-
term key is compromised. PFS accomplishes this by enforcing the derivation of a
new key for each and every session.

This means that when the private key gets compromised it cannot be used to
decrypt recorded SSL traffic.

The cipher suites that provide Perfect Forward Secrecy are those that use an
ephemeral form of the Diffie-Hellman key exchange. Their disadvantage is their
overhead, which can be improved by using the elliptic curve variants.

The following two ciphersuites are recommended by me, and the latter by [the
Mozilla Foundation][14].

The recommended cipher suite:



   ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;


The recommended cipher suite for backwards compatibility (IE6/WinXP):



   ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";


If your version of OpenSSL is old, unavailable ciphers will be discarded
automatically. Always use the full ciphersuite above and let OpenSSL pick the
ones it supports.

The ordering of a ciphersuite is very important because it decides which
algorithms are going to be selected in priority. The recommendation above
prioritizes algorithms that provide perfect forward secrecy.

Older versions of OpenSSL may not return the full list of algorithms. AES-GCM
and some ECDHE are fairly recent, and not present on most versions of OpenSSL
shipped with Ubuntu or RHEL.

#### Prioritization logic

 * ECDHE+AESGCM ciphers are selected first. These are TLS 1.2 ciphers. No known attack currently target these ciphers.
 * PFS ciphersuites are preferred, with ECDHE first, then DHE.
 * AES 128 is preferred to AES 256. There has been [discussions][15] on whether AES256 extra security was worth the cost , and the result is far from obvious. At the moment, AES128 is preferred, because it provides good security, is really fa st, and seems to be more resistant to timing attacks.
 * In the backward compatible ciphersuite, AES is preferred to 3DES. BEAST attacks on AES are mitigated in TLS 1.1 and a bove, and difficult to achieve in TLS 1.0. In the non-backward compatible ciphersuite, 3DES is not present.
 * RC4 is removed entirely. 3DES is used for backward compatibility. See discussion in [#RC4_weaknesses][16]

#### Mandatory discards

 * aNULL contains non-authenticated Diffie-Hellman key exchanges, that are subject to Man-In-The-Middle (MITM) attacks
 * eNULL contains null-encryption ciphers (cleartext)
 * EXPORT are legacy weak ciphers that were marked as exportable by US law
 * RC4 contains ciphers that use the deprecated ARCFOUR algorithm
 * DES contains ciphers that use the deprecated Data Encryption Standard
 * SSLv2 contains all ciphers that were defined in the old version of the SSL standard, now deprecated
 * MD5 contains all the ciphers that use the deprecated message digest 5 as the hashing algorithm

### Extra settings

Make sure you also add these lines:



   ssl_prefer_server_ciphers on;
   ssl_session_cache shared:SSL:10m;


When choosing a cipher during an SSLv3 or TLSv1 handshake, normally the client's
preference is used. If this directive is enabled, the server's preference will
be used instead.

[More info on ssl _prefer_ server_ciphers][17] [More info on ssl_ciphers][18]

### Forward Secrecy & Diffie Hellman Ephemeral Parameters

The concept of forward secrecy is simple: client and server negotiate a key that
never hits the wire, and is destroyed at the end of the session. The RSA private
from the server is used to sign a Diffie- Hellman key exchange between the
client and the server. The pre-master key obtained from the Diffie-Hellman
handshake is then used for encryption. Since the pre-master key is specific to a
connection between a client and a server, and used only for a limited amount of
time, it is called Ephemeral.

With Forward Secrecy, if an attacker gets a hold of the server's private key, it
will not be able to decrypt past communications. The private key is only used to
sign the DH handshake, which does not reveal the pre- master key. Diffie-Hellman
ensures that the pre-master keys never leave the client and the server, and
cannot be intercepted by a MITM.

All versions of nginx as of 1.4.4 rely on OpenSSL for input parameters to
Diffie-Hellman (DH). Unfortunately, this means that Ephemeral Diffie- Hellman
(DHE) will use OpenSSL's defaults, which include a 1024-bit key for the key-
exchange. Since we're using a 2048-bit certificate, DHE clients will use a
weaker key-exchange than non-ephemeral DH clients.

We need generate a stronger DHE parameter:



   openssl dhparam -out /etc/ssl/certsdhparam.pem 4096


And then tell nginx to use it for DHE key-exchange:



   ssl_dhparam /etc/ssl/certs/dhparam.pem;
   ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0


### OCSP Stapling

When connecting to a server, clients should verify the validity of the server
certificate using either a Certificate Revocation List (CRL), or an Online
Certificate Status Protocol (OCSP) record. The problem with CRL is that the
lists have grown huge and takes forever to download.

OCSP is much more lightweight, as only one record is retrieved at a time. But
the side effect is that OCSP requests must be made to a 3rd party OCSP responder
when connecting to a server, which adds latency and potential failures. In fact,
the OCSP responders operated by CAs are often so unreliable that browser will
fail silently if no response is received in a timely manner. This reduces
security, by allowing an attacker to DoS an OCSP responder to disable the
validation.

The solution is to allow the server to send its cached OCSP record during the
TLS handshake, therefore bypassing the OCSP responder. This mechanism saves a
roundtrip between the client and the OCSP responder, and is called OCSP
Stapling.

The server will send a cached OCSP response only if the client requests it, by
announcing support for the status_request TLS extension in its CLIENT HELLO.

Most servers will cache OCSP response for up to 48 hours. At regular intervals,
the server will connect to the OCSP responder of the CA to retrieve a fresh OCSP
record. The location of the OCSP responder is taken from the Authority
Information Access field of the signed certificate.

[View my tutorial on enabling OCSP stapling on NGINX][19]

### HTTP Strict Transport Security

When possible, you should enable [HTTP Strict Transport Security (HSTS)][20],
which instructs browsers to communicate with your site only over HTTPS.

[View my article on HTST to see how to configure it.][10]

### HTTP Public Key Pinning Extension

You should also enable the [HTTP Public Key Pinning Extension][11].

Public Key Pinning means that a certificate chain must include a whitelisted
public key. It ensures only whitelisted Certificate Authorities (CA) can sign
certificates for `*.example.com`, and not any CA in your browser store.

I've written an article about it that has background theory and configuration
examples for Apache, Lighttpd and NGINX: [https://raymii.org/s/articles/HTTP
_Public_ Key _Pinning_ Extension_HPKP.html][12]

### Poodle and TLS-FALLBACK-SCSV

SSLv3 allows exploiting of the [POODLE][21] bug. This is one more major reason
to disable this.

Google have proposed an extension to SSL/TLS named [TLS _FALLBACK_ SCSV][22]
that seeks to prevent forced SSL downgrades. This is automatically enabled if
you upgrade OpenSSL to the following versions:

 * OpenSSL 1.0.1 has TLS _FALLBACK_ SCSV in 1.0.1j and higher.
 * OpenSSL 1.0.0 has TLS _FALLBACK_ SCSV in 1.0.0o and higher.
 * OpenSSL 0.9.8 has TLS _FALLBACK_ SCSV in 0.9.8zc and higher.

[More info on the NGINX documentation][23]

### The BEAST attack and RC4

In short, by tampering with an encryption algorithm's CBC - cipher block
chaining - mode's, portions of the encrypted traffic can be secretly decrypted.
More info on the above link.

Recent browser versions have enabled client side mitigation for the beast
attack. The recommendation was to disable all TLS 1.0 ciphers and only offer
RC4. However, [RC4 has a growing list of attacks against
it],(http://www.isg.rhul.ac.uk/tls/) many of which have crossed the line from
theoretical to practical. Moreover, there is reason to believe that the NSA has
broken RC4, their so-called "big breakthrough."

Disabling RC4 has several ramifications. One, users with shitty browsers such as
Internet Explorer on Windows XP will use 3DES in lieu. Triple- DES is more
secure than RC4, but it is significantly more expensive. Your server will pay
the cost for these users. Two, RC4 mitigates BEAST. Thus, disabling RC4 makes
TLS 1.0 users susceptible to that attack, by moving them to AES-CBC (the usual
server-side BEAST "fix" is to prioritize RC4 above all else). I am confident
that the flaws in RC4 significantly outweigh the risks from BEAST. Indeed, with
client-side mitigation (which Chrome and Firefox both provide), BEAST is a
nonissue. But the risk from RC4 only grows: More cryptanalysis will surface over
time.

### Factoring RSA-EXPORT Keys (FREAK)

FREAK is a man-in-the-middle (MITM) vulnerability discovered by a group of
cryptographers at [INRIA, Microsoft Research and IMDEA][24]. FREAK stands for
"Factoring RSA-EXPORT Keys."

The vulnerability dates back to the 1990s, when the US government banned selling
crypto software overseas, unless it used export cipher suites which involved
encryption keys no longer than 512-bits.

It turns out that some modern TLS clients - including Apple's SecureTransport
and OpenSSL - have a bug in them. This bug causes them to accept RSA export-
grade keys even when the client didn't ask for export-grade RSA. The impact of
this bug can be quite nasty: it admits a 'man in the middle' attack whereby an
active attacker can force down the quality of a connection, provided that the
client is vulnerable and the server supports export RSA.

There are two parts of the attack as the server must also accept "export grade
RSA."

The MITM attack works as follows:

 * In the client's Hello message, it asks for a standard 'RSA' ciphersuite.
 * The MITM attacker changes this message to ask for 'export RSA'.
 * The server responds with a 512-bit export RSA key, signed with its long-term key.
 * The client accepts this weak key due to the OpenSSL/SecureTransport bug.
 * The attacker factors the RSA modulus to recover the corresponding RSA decryption key.
 * When the client encrypts the 'pre-master secret' to the server, the attacker can now decrypt it to recover the TLS 'm aster secret'.
 * From here on out, the attacker sees plaintext and can inject anything it wants.

The ciphersuite offered here on this page does not enable EXPORT grade ciphers.
Make sure your OpenSSL is updated to the latest available version and urge your
clients to also use upgraded software.

### Logjam (DH EXPORT)

[Researchers][25] from several universities and institutions conducted a study
that found an issue in the TLS protocol. In a report the researchers report two
attack methods.

Diffie-Hellman key exchange allows that depend on TLS to agree on a shared key
and negotiate a secure session over a plain text connection.

With the first attack, a man-in-the-middle can downgrade a vulnerable TLS
connection to 512-bit export-grade cryptography which would allow the attacker
to read and change the data. The second threat is that many servers and use the
same prime numbers for Diffie-Hellman key exchange instead of generating their
own unique DH parameters.

The team estimates that an academic team can break 768-bit primes and that a
nation-state could break a 1024-bit prime. By breaking one 1024-bit prime, one
could eavesdrop on 18 percent of the top one million HTTPS domains. Breaking a
second prime would open up 66 percent of VPNs and 26 percent of SSH servers.

Later on in this guide we generate our own unique DH parameters and we use a
ciphersuite that does not enable EXPORT grade ciphers. Make sure your OpenSSL is
updated to the latest available version and urge your clients to also use
upgraded software. Updated browsers refuse DH parameters lower than 768/1024 bit
as a fix to this.

[Cloudflare has a detailed guide][26] on logjam.

### Heartbleed

Heartbleed is a security bug disclosed in April 2014 in the OpenSSL cryptography
library, which is a widely used implementation of the Transport Layer Security
(TLS) protocol. Heartbleed may be exploited regardless of whether the party
using a vulnerable OpenSSL instance for TLS is a server or a client. It results
from improper input validation (due to a missing bounds check) in the
implementation of the DTLS heartbeat extension (RFC6520), thus the bug's name
derives from "heartbeat". The vulnerability is classified as a buffer over-read,
a situation where more data can be read than should be allowed.

What versions of the OpenSSL are affected by Heartbleed?

Status of different versions:

 * OpenSSL 1.0.1 through 1.0.1f (inclusive) are vulnerable
 * OpenSSL 1.0.1g is NOT vulnerable
 * OpenSSL 1.0.0 branch is NOT vulnerable
 * OpenSSL 0.9.8 branch is NOT vulnerable

The bug was introduced to OpenSSL in December 2011 and has been out in the wild
since OpenSSL release 1.0.1 on 14th of March 2012. OpenSSL 1.0.1g released on
7th of April 2014 fixes the bug.

By updating OpenSSL you are not vulnerable to this bug.

### SSL Compression (CRIME attack)

The CRIME attack uses SSL Compression to do its magic. SSL compression is turned
off by default in nginx 1.1.6+/1.0.9+ (if OpenSSL 1.0.0+ used) and nginx
1.3.2+/1.2.2+ (if older versions of OpenSSL are used).

If you are using al earlier version of nginx or OpenSSL and your distro has not
backported this option then you need to recompile OpenSSL without ZLIB support.
This will disable the use of OpenSSL using the DEFLATE compression method. If
you do this then you can still use regular HTML DEFLATE compression.

### Conclusion

If you have applied the above config lines you need to restart nginx:



   # Check the config first:
   /etc/init.d/nginx configtest
   # Then restart:
   /etc/init.d/nginx restart


Now use the [SSL Labs test][13] to see if you get a nice A. And, of course, have
a safe, strong and future proof SSL configuration!

[Also read the Mozilla page on the subject][14]

  [1]: https://raymii.org/s/inc/img/ssl-labs-3.png
  [2]: https://www.ssllabs.com/ssltest/analyze.html?d=raymii.org
  [3]: https://raymii.org/s/software/OpenSSL_Decoder.html
  [4]: https://cipherli.st/
  [5]: https://www.digitalocean.com/?refcode=7435ae6b8212
  [6]: http://blog.ivanristic.com/2014/01/ssl-labs-stricter-security-requirements-for-2014.html
  [7]: https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html
  [8]: https://raymii.org/s/tutorials/Strong_SSL_Security_On_lighttpd.html
  [9]: http://www.bsdnow.tv/episodes/2014_08_20-engineering_nginx
  [10]: https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html
  [11]: https://wiki.mozilla.org/SecurityEngineering/Public_Key_Pinning
  [12]: https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html
  [13]: https://www.ssllabs.com/ssltest/
  [14]: https://wiki.mozilla.org/Security/Server_Side_TLS
  [15]: http://www.mail-archive.com/dev-tech-crypto@lists.mozilla.org/msg11247.html
  [16]: https://wiki.mozilla.org/Security/Server_Side_TLS#RC4_weaknesses
  [17]: http://wiki.nginx.org/HttpSslModule#ssl_prefer_server_ciphers
  [18]: http://wiki.nginx.org/HttpSslModule#ssl_ciphers
  [19]: https://raymii.org/s/tutorials/OCSP_Stapling_on_nginx.html
  [20]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
  [21]: https://raymii.org/s/articles/Check_servers_for_the_Poodle_bug.html
  [22]: https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
  [23]: http://wiki.nginx.org/HttpSslModule#ssl_protocols
  [24]: https://www.smacktls.com/
  [25]: https://weakdh.org/
  [26]: https://blog.cloudflare.com/logjam-the-latest-tls-vulnerability-explained/

---

License:
All the text on this website is free as in freedom unless stated otherwise.
This means you can use it in any way you want, you can copy it, change it
the way you like and republish it, as long as you release the (modified)
content under the same license to give others the same freedoms you've got
and place my name and a link to this site with the article as source.

This site uses Google Analytics for statistics and Google Adwords for
advertisements. You are tracked and Google knows everything about you.
Use an adblocker like ublock-origin if you don't want it.

All the code on this website is licensed under the GNU GPL v3 license
unless already licensed under a license which does not allows this form
of licensing or if another license is stated on that page / in that software:

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

Just to be clear, the information on this website is for meant for educational
purposes and you use it at your own risk. I do not take responsibility if you
screw something up. Use common sense, do not 'rm -rf /' as root for example.
If you have any questions then do not hesitate to contact me.

See https://raymii.org/s/static/About.html for details.