Improve the Security of your Nginx SSL Web Server

Learn how to harden the SSL Configuration of Nginx.

 

“Three things can not hide for long: the Moon, the Sun and the Truth.” ― Gautama Buddha

1. Introduction

In previous articles, we discussed how to create a CSR to obtain an SSL certificate, as well as how to configure Nginx web server with that certificate. Let us now discuss improving the configuration of Nginx for better security.

We assume that you have setup Nginx as described in the earlier article. Specifically, we add the SSL configuration directives to the file /etc/nginx/snippets/ssl.conf and this file is included in the server configuration. So we concentrate on making changes to this file.

As of now, the file looks like this.

ssl_certificate /etc/nginx/ssl/example.com.bundle.cer;
ssl_certificate_key /etc/nginx/ssl/example.com.keynopass;

The first is all the certificates in the certificate chain, starting with our own certificate first. The second file is the RSA private key with which the CSR was signed.

2. Disable Weak Ciphers

First, we disable weak ciphers and specify the list of ciphers that Nginx should use. This is based on new vulnerabilities discovered in the disabled ciphers.

ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256: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";

3. Enable TLS and Disable SSL

Now we turn TLS on and disable SSL. SSL is an older protocol for HTTPS and has been deprecated. Here is the relevant information (from the previous article):

Both SSL and TLS are protocols that provide the authentication and data encryption as a part of HTTPS. SSL is an older protocol has gone through three versions: SSL 1.0 was internal to Netscape who developed it, SSL 2.0 in 1995 and SSL v3 in 1996. TLS 1.0 was based on SSL 3.0 and is currently in use. SSLv2 was deprecated in 2011 and SSLv3 in 2015 as they contained vulnerabilities. This means you need to turn of usage of these protocols in Apache, leaving on TLS on the table.

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

4. Cache Previous Session

Each SSL connection begins with the browser and server exchanging information back and forth a number of times. This is a very time consuming process. When you leave the site for some time and return to it later, this negotiation has to be performed again.

Wouldn’t it be nice if the session could be just resumed within a certain time? That is what this section does. It request nginx to set aside 10MB for the session cache and a timeout of 10 minutes. Adjust these values if you need to.

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

5. OCSP Stapling

What is OCSP (Online Certificate Status Protocol)?

When the browser encounters an SSL certificate, it must verify that the certificate is valid and has not been revoked. It does this by asking the certificate issuer, who is the authority for maintaining such information. The certifying authority (CA) responds back with information regarding the validity of the certificate. This protocol is known as the OCSP – Online Certificate Status Protocol.

What is OCSP Stapling?

This process of contacting the CA is time-consuming. This burden can be shifted to the server, who can contact the CA and cache the response. When the browser connects with the server, the server can send the cached response. The response is signed by the CA and time-stamped so the browser can trust it. This eliminates the need for the browser to contact the CA. Win for the user and faster browsing!

Turn on this wonderful option in your nginx server by using the following statements.

ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7

6. HTTP Strict Transport Security (HSTS)

Wouldn’t it be nice to always surf in HTTPS, even though you forget to enter https at the beginning of the URL? That is what HTTP Strict Transport Security does. It declares to the browser that it should only use HTTPS to interact with the server.

Turn on this option as shown below. The max-age parameter specifies the time the browser is required to follow this instruction.

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";

7. Prevent Clickjacking

Clickjacking is a technique where a user is offered something, such as a free download, to click on a button. The button however invokes some other action not intended by the user. This is accomplished by placing well-known content (such as your bank’s login screen) into a frame, but redirecting the click elsewhere.

Prevent this nefarious activity by disabling your web site content into appearing in an IFrame, Object, etc.

add_header X-Frame-Options DENY;

If you want to use iframes on your own website and embed your content in a frame, use the following instead:

add_header X-Frame-Options SAMEORIGIN;

8. Disable MIME Sniffing

MIME Sniffing refers to a browser attempting to determine the content type of a byte stream by checking the first few bytes for known signatures. This, however, is a security hole and allows an attacker to trigger unexpected (by you!) attacks against the browser.

Prevent browser MIME sniffing by using this option.

add_header X-Content-Type-Options nosniff;

9. Use DNS Resolver

Using a DNS resolver with statements shown below avoids problems when you use hostnames in your nginx config (perhaps as a reverse proxy), and the host changes its IP (as is common with Amazon EC2).

The following statement uses Google’s DNS servers. You can, of course, use your own if you have them.

resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 5s;

10. Generate Diffie-Hellman Parameters

Diffie-Hellman is a key exchange protocol which is used by the server and the browser to exchange keys for each session. Since Nginx relies on openssl for the parameters to Diffie-Hellman, it uses openssl’s DH parameters. That brings the key size for DH down to 1024 bits. Our certificate is however 2048-bits in strength. So the key exchange proceeds with keys of 1024 bits.

To remedy this situation, you should generate DH params using the command:

cd /etc/nginx/ssl
openssl dhparam -out dhparam.pem 4096

And tell Nginx to use the DH parameters generated.

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

11. Verify Configuration

Now it is time to restart the server and check that SSL is working.

Restart the server on Ubuntu 14.04 as follows:

service nginx restart

Restart the server on Ubuntu 16.04 with this command:

systemctl restart nginx

Once the SSL is verified working properly, you can use the Qualys SSL Checker to make sure the server is secure.

With these improvements, we get an A+ on the Qualys SSL Checker.

 

Geeks, you think you can do better than that? Let’s have it in the comments!

Conclusion

This article showed you how to successively improve the configuration of your Nginx SSL. It involves making use of information regarding vulnerabilities detected currently in SSL. When you follow these instructions, you should have an optimal performing SSL web site.

Leave a Reply

Your email address will not be published. Required fields are marked *