Published on

Nginx SSL notes

Here are some (useful) notes about SSL and security with Nginx. This is just a collection of tips, nothing more...

A SSL cert

For certificates for this and also other hosts, I signed up for StartSSL. In contrast to other providers, they offer a free SSL certificate for one domain plus subdomain. Before that, I had certs from CaCert which is also nice, but the root certificate is missing in all major browsers.

I won't describe the actual process of how to get a certificate from StartSSL because the may change it over time. This is just about how Nginx works with SSL.

So now you have a certificate from $provider. For Nginx you have to create a chain with your private key, your certificate and the StartSSL cert, in that order. Because of this special format, I store all certificates Nginx is using in /etc/nginx/ssl.

$> cat example.com.key sub.class1.server.ca.pem example.com.pem > /etc/nginx/ssl/example.com.pem

If you've done that, configuring Nginx to use it is fairly simple:

server {
    listen 443;
    ssl_certificate /etc/nginx/ssl/example.com.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
}

Ciphers

HTTPS is ready to go, but which ciphers are actually used? Nginx has the following default rules (Taken from http://wiki.nginx.org/HttpSslModule#ssl_ciphers):

ssl_ciphers   HIGH:!aNULL:!MD5;

List available ciphers:

$> openssl ciphers

Cipher list format explained: http://openssl.org/docs/apps/ciphers.html

Check for negotiated chipher

If you'd like to see which cipher is negotiated between you and your host, openssl has a very nice way to do that. Just run

openssl s_client -host example.com -port 443

or, when you need to specify a hostname for SNI for example, run

openssl s_client -host example.com -port 443 -servername example.com

Comparison

Okay, so now we know which cipher is usually negotiated. But how are the "others" doing?

$> openssl s_client -host google.com -port 443
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-RC4-SHA
$> openssl s_client -host facebook.com -port 443
New, TLSv1/SSLv3, Cipher is AES128-SHA
$> openssl s_client -host news.ycombinator.com -port 443
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
$> openssl s_client -host twitter.com -port 443
New, TLSv1/SSLv3, Cipher is RC4-SHA

As one could see, different (default) cyphers are used for different reasons. It is always a tradeoff between performance and security.

The cypher kEDH for example is known as a rather expensive one and many people disable it for this very reason. In some cases this would actually make sense, when you have to deal with lots of new connections and the host is at its limits.

Session Caching

Sessions (since SSLv2) allow to create connections with encryption keys based on the same key data. Once the (complete) negotiation was successful, further connections within the same session can use this data to calculate the encryption keys.

Nginx supports this:

# Shared cache of 10MB
ssl_session_cache    shared:SSL:10m;
# Default timeout is 5m
ssl_session_timeout  10m;

HTTP Strict Transport Security

HSTS (draft) is something like a permanent redirect to HTTPS: Once a user visits a website via HTTPS and receives a HSTS header, it declares itself that this site is only accessible over a secure connection. The next time, the user wants to access the site via HTTP, the browser automatically switchs to HTTP (unless the HSTS preference hasn't expired). It only works with HTTPS, it is not allowed to send this header over HTTP.

Nginx configuration:

# The browser should remember this preference for 1 year
add_header Strict-Transport-Security max-age=31536000;
# If you'd like to include subdomains:
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

X-Frame-Options

This header specifies how a site can be used in a frame. This is also a draft and should help against Clickjacking.

# If not otherwise specified
add_header X-Frame-Options ALLOW;
# Sameorigin-policy
add_header X-Frame-Options SAMEORIGIN;
# Never allow
add_header X-Frame-Options DENY;