Guide to Nginx + SSL + SPDY

Intro

a short documentation on how to setup and run nginx as SSL-Gateway/Offload, including SPDY. Beside basic configuration this guide covers HSTS-Headers, Perfect Forward Secrecy (PFS) and the latest and greatest ssl-based attacks like Heartbleed, BREACH, CRIME, BEAST and Lucky Thirteen. This guide shows how to configure various ssl-related options and performance-tuning, but doesnt explain much about the why; more details and references for each suggestion are available in each section.

the suggestions regarding cipher-suites and mitigation are found on different sites and cross-checked against various sources, especially tested via ssllabs.com to produce an A+ - ranking. if you rely on strong security you should let security-experts evaluate each suggestion. Additionally, we advise you to conduct your own performance/ssl-tests, expecially when trying different cipher-suites.

Notes and suggestions are valid as of Apr 2014.

disclaimer: the information presented herein is without any guarantees and we’ll take no responsibility if any harm happens to you or your users. If you find any factual problems, please contact us immediately and we will fix it ASAP.

When to use HTTPS/SSL

If you already have some parts of your website running in SSL, like login- or signup-forms, you should consider to switch to HTTPS for all parts of your site, if you haven't already; this blogpost explains why.

Whenever you use login/authentication you should enable SSL site-wide to protect your users from MITM-attacks and session-takeovers.

If you want to ensure the authenticity and/or integrity of your website from your users point-of-view you should enable SSL.

How to use HTTPS/SSL

For each virtualhost:443 you want to run under HTTPS you should create a corresponding server {} - directive that listens on HTTP and redirects all traffic to https://.... this is expecially usefull if you:

If you use SSL on some part of your website already, you should enable SSL for all parts of your website. Really.

How to generate / obtain an SSL-certificate

For security it doesnt matter if you use a self-signed certificate or a certificate from a trusted authority. StartSSL.com offers free domain-validated certs; for extended-validated (EV) or wildcard - certs you might ask your hosting-provider.

You'll find a whole lot of guides on how to create a CSR (Certificate Signing Request) that is needed to obtain a cert from a trusted CA or how to generate a self-signed certificate; see this guide on openssl.com, this guide from akadia.com or this complete guide from didierstevens.com

When generating your CSR be sure to have 2048 bit key size; it is required by certificates that will expire after October 2013 src: verisign

NGINX + SSL - Basics

Since Nginx version 0.7.14 the preferred way of enabling SSL is by using the ssl parameter of the listen directive.

There is a 3rd-party-module (nginx-openssl-version) available to check for the openssl-version used; you might want to use it to assure a certain version for your self-compiled nginx. This module should work with static or dynamically linked openssl-versions, thus ensuring integrity over availabilty.

#
# standalone HTTPS-server + http-redirect; recommended setup
# 

server {
    listen              443 ssl;
    server_name         secure.example.com;

    ssl_certificate     /etc/ssl/secure.example.com.crt;
    ssl_certificate_key /etc/ssl/secure.example.com.key;
    ...
}

# http-redirects to https

server {
    listen              80 default_server;
    server_name         secure.example.com;
    return 301 https://$host$request_uri;


}

###############################################
#
# combined http/https-server
# recommended, if you arent targetable by BREACH/BEAST-attacks

server {
    listen              80;
    listen              443 ssl;
    server_name         secure.example.com;
    ssl                 on;
    ssl_certificate     /etc/ssl/secure.example.com.crt;
    ssl_certificate_key /etc/ssl/secure.example.com.key;

    # force https-redirects
    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }

    ...
}

Multiple HTTPS - Servers/Certs

Works-everywhere - solution

server {
    listen          192.168.1.1:443 ssl;
    server_name     secure1.example.com;
    ssl_certificate secure1.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443 ssl;
    server_name     secure2.example.com;
    ssl_certificate secure2.example.com.crt;
    ...
}

Using Wildcard/multiple certificates with several names

When using a configuration like this it's more efficient memory wise to place the certificate file containing the certificate(s) for all domain names and the corresponding private key file directives in a http context, such that it's inherited by all active servers/virtual hosts:

ssl_certificate      secure.example.com.crt;
ssl_certificate_key  secure.example.com.key;

server {
  listen           80;
  server_name      www.example.com;
  ...
}

server {
  listen           443 default_server ssl;
  server_name      secure.example.com;
  ...
}

server {
  listen           80;
  listen           443;
  server_name      images.example.com;
  ...
}

SNI - ServerNameIndication

supporting browsers

doesnt work

intermediate-certs (thawte etc) using an SSL certificate chain)

server {
    ...
    ssl_certificate     www.example.com.crt-combined;
    ...
}

Choosing the right cipher-suites / Perfect Forward Security (PFS)

Perfect Forward Secrecy

(Perfect) 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.

SSLLabs has a very detailed article on PFS: Deploying Forward Secrecy and also published a guide on Configuring Apache, Nginx, and OpenSSL for Forward Secrecy

Another interesting read is SSL/TLS & Perfect Forward Secrecy from Vincent Bernat.

While testing different cipher-suites we only found the ssllabs-suggestion fully enabling PFS when checking with ssllabs.com/ssltest.

Hasgeek.com - suggestions creating the best Rank @ ssllabs [Rank A, 100/90/100/90]

doesnt work

server {
    ...
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    # nginx.org - defaults; works always, limited PFS
    ssl_ciphers HIGH:!aNULL:!MD5;

    # suggestion from sslabs / including PFS, good compatibility
    #ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;


    # additional cipher_suite - suggestions

    # from nginx-ml - no PFS
    #ssl_ciphers HIGH:!SSLv2:!MEDIUM:!LOW:!EXP:!RC4:!DSS:!aNULL:@STRENGTH;

    # nginx-default-for-static - no PFS
    #ssl_ciphers RC4:HIGH:!aNULL:!MD5;


    # suggestion from hasgeek.com
    #ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;

    # bare minimum for BEAST-mitigation + PFS
    #ssl_ciphers !aNULL:!LOW:!MD5:!EXP:RC4:AES256:3DES:AES128:SEED:CAMELLIA;

    # PFS and most secure ciphers (think about using TLS1.2 only)
    # suggestion from code-bear.com
    #ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:RC4-SHA;

    # PFS + BEAST-mitigation 
    # suggestion from hynek.me
    #ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:RC4-SHA;


    # fast and secure, BEAST-mitigation but no PFS?
    # suggestion from http://unhandledexpression.com
    #ssl_ciphers ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM;

    #
    # suggestion my mozilla-server-team - good compatibility, pfs
    #
    #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
    ...

}

SSL-analysis and optimization

optimizing for better SSL-performance

http {
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    server_tokens       off;



    server {
        ssl on;
        ...
        gzip on;
        expires 1d;
        ...
        keepalive_timeout   70;
        ...
        # nginx-default-for-static - no PFS
        #ssl_ciphers RC4:HIGH:!aNULL:!MD5;
        ...
    }

}

testing SSL-setups

$ testssl.sh smtp.gmail.com

testssl.sh - sample - output


$ ./cipherscan www.mare-system.de:443
prio  ciphersuite                  protocols              pfs_keysize
1     ECDHE-RSA-AES128-GCM-SHA256  TLSv1,TLSv1.1,TLSv1.2  ECDH,P-256,256bits
2     ECDHE-RSA-AES256-GCM-SHA384  TLSv1,TLSv1.1,TLSv1.2  ECDH,P-256,256bits
3     DHE-RSA-AES128-GCM-SHA256    TLSv1,TLSv1.1,TLSv1.2  
4     DHE-RSA-AES256-GCM-SHA384    TLSv1,TLSv1.1,TLSv1.2
5     ECDHE-RSA-AES128-SHA256      TLSv1,TLSv1.1,TLSv1.2  ECDH,P-256,256bits
6     ECDHE-RSA-AES128-SHA         TLSv1,TLSv1.1,TLSv1.2  ECDH,P-256,256bits
7     ECDHE-RSA-AES256-SHA384      TLSv1,TLSv1.1,TLSv1.2  ECDH,P-256,256bits
8     ECDHE-RSA-AES256-SHA         TLSv1,TLSv1.1,TLSv1.2  ECDH,P-256,256bits
...
# testing ssl_config
$ openssl s_client -host www.mare-system.de -port 443

# testing for slow ciphers
$ openssl s_client -host HOSTNAME -port 443 | grep DHE

HSTS - Header

HTTP Strict Transport Security (HSTS) is a web security policy mechanism whereby a web server declares that complying user agents (such as a web browser) are to interact with it using only secure HTTPS connections HSTS is an IETF standards track protocol and is specified in RFC 6797.

The HSTS Policy is communicated by the server to the user agent via a HTTP response header field named "Strict-Transport-Security". HSTS Policy specifies a period of time during which the user agent shall access the server in only secure fashion.

server {
    ...
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    ...
}

SPDY

CAUTION: SPDY-Issues with the stable branch 1.4.x:

SPDY (pronounced speedy) is an open networking protocol developed primarily at Google for transporting web content. The goal of SPDY is to reduce web page load time. This is achieved by prioritizing and multiplexing the transfer of web page subresources so that only one connection per client is required. TLS encryption is nearly ubiquitous in SPDY implementations, and transmission headers are gzip-or DEFLATE-compressed by design. src: wikipedia

You can use selfsigned or CA-signed ssl-certificates with SPDY.

nginx supports SPDY - protocol in an experimental version since 1.3.15 and is available in stable-branch since 1.4.0. because it's not marked stable yet this features has to be switched on during compilation:

./configure ... --with-http_spdy_module --with-http_ssl_module ... 

Requirements

SPDY can only be served via https and depends on spdy-aware browsers (like curent firefox and chrome). if spdy-servers detect a non-spdy-browser the connection is switched to a standard HTTPS-session to prevent compatibilty-issues.

Workaround for outdated OpenSSL-versions

./configure ... --with-http_spdy_module --with-http_ssl_module  \
                --with-openssl=/path/to/openssl_source/ ... 

check if spdy is enabled

config

server {

    listen      443 ssl spdy;
    #add_header  Alternate-Protocol  443:npn-spdy/2;

}

SSL attacks and mitigations

Heartbleed

A Bug was published 2014-04-07 with a critical vuln in OpenSSL, allowing remote attackers to read up to 64k of memory of affected systems, including a possible compromise of ssl-server-keys. We were able to extract user-logins and sessioninformations from a major webmail-provider; so this bug must be considered critical, even if you have PFS implemented

affected versions:

If you run nginx from your distro, you should update asap; updated versions are available for all major distributions as of 2014-04-08 (please dont forget to restart services; if possible, the whole server).

If you run an nginx-version with static-compiled openssl you should rebuild and deploy your updated binaries. If you cannot recompile with an updated openssl-version, you can rebuild openssl with the -DOPENSSL_NO_HEARTBEATS - flag to disable the affected extension.

There is no mitigation or workaround; if your version is affected you need to update.

The following steps are suggested to recover from that bug:

  1. Patch vulnerable systems and reboot
  2. Regenerate new private keys.
  3. Submit new CSR to your CA.
  4. Obtain and install new signed certificate.
  5. Revoke old certificates.

Tests

local checks (please note: YMMV on all suggested commands given here):

[ me@host :~] > nginx -V 2>&1 | grep "\-\-with-openssl" 
configure arguments: --conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/sbin/nginx 
...  --with-http_ssl_module ...  --with-openssl=/path/to/openssl ...
[ me@host :~] > openssl version
OpenSSL 1.0.1g 7 Apr 2014
...
nginx: [emerg] OpenSSL runtime too old; asked for 1.0.2g, got: OpenSSL 1.0.1g 7 Apr 2014
...

Checks against remote Servers:

BREACH

BREACH is an attack against SSL-encrypted sites that works if you have an HTTP response body that meets all of the following requirements:

Server-side mitigation is easy (see this discussion @ nginx - mailinglist) but would probably impact page_load_time:

The BREACH-Team lists it's own suggestions for mitigation-strategies, but these would require changes within the webapp:

  1. Disabling HTTP compression
  2. Separating secrets from user input
  3. Randomizing secrets per request
  4. Masking secrets (effectively randomizing by XORing with a random secret per request)
  5. Protecting vulnerable pages with CSRF
  6. Length hiding (by adding random number of bytes to the responses)
  7. Rate-limiting the requests

Another Writeup on BREACH might be found here @ detectify.

BEAST / Lucky13

RC4 was considered a good solution for BEAST-mitigation, but since Lucky13 was developed TLS1.0 should be avoided, if possible. according to this post from Mr. SSL, Ivan Ristic, RC4 is considered not secure anymore. There's just one mitigation for this: use TLS1.2. The problem: TLS 1.2 is not yet widely supported by browsers. Although RC4-breakage is considered academic this statement could (and probabyl will) be invalid within the next years, so upgrading clients and servers to TLS 1.2 should happen as soon as possible.

"The difficulty is that, for public web sites that need to support a wide user base, there is practically nothing 100% secure they can use to replace RC4. We now have no choice but to accept that, no matter what settings we use, some segment of the user base will be at risk." RC4 in TLS is Broken: Now What? by Ivan Ristic

The attacks can only be carried out by a determined attacker who can generate sufficient sessions for the attacks. They recover a limited amount of plaintext. In this sense, the attacks do not pose a significant danger to ordinary users of TLS or WPA/TKIP in their current form. However, it is a truism that attacks only get better with time, and we anticipate significant further improvements to our attacks. On the Security of RC4 in TLS and WPA by Nadhem AlFardan, Dan Bernstein, Kenny Paterson, Bertram Poettering, Jacob Schuldt

At the moment (as of 2013) the common solution against BEAST is considered RC4, but update to TLS1.2 and using different cipher-suites should be implemented as soon as possible. If you have to support a wide range of OS and browsers, Lucky(13) You :)

RSA gives a short intro into the Lucky13 - problem in a blogpost: Secure Crypto: "Lucky Thirteen" Attack

server {
    ...
    ssl_prefer_server_ciphers on;

    # for more valid cipher-suites see [ complete and commented sample ] below
    # bare minimum fore BEAST - mitigation
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;

    ...
}

CRIME

SSL Client-Authentication with Nginx

# credits: Nathan Good / https://github.com/nategood/sleep-tight
#
# Create the CA Key and Certificate for signing Client Certs
openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

# Create the Server Key, CSR, and Certificate
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr

# We're self signing our own server cert here.  This is a no-no in production.
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

# Create the Client Key and CSR
openssl genrsa -des3 -out client.key 1024
openssl req -new -key client.key -out client.csr

# Sign the client certificate with our CA cert.  Unlike signing our own server cert, this is what we want to do.
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
server {
    listen        443;
    ssl on;

    ...
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client optional;

    location /api/ {
        ssl_verify_client on;
        ...

    }


    location /fastcgi/ {
        root           /var/www/example.com/html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_param  SCRIPT_FILENAME /var/www/example.com/lib/Request.class.php;
        fastcgi_param  VERIFIED $ssl_client_verify;
        fastcgi_param  DN $ssl_client_s_dn;
        ...

    }
}
curl -v -s -k --key client.key --cert client.crt https://secure.example.c/api/request/

complete and commented config-example

#openssl_version_minimum 1.0.1g;

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

    server_tokens       off;
    keepalive_timeout   60;

    # http-redirects to https; even if using of hsts; 
    # usefull if users are typing your server-name w/out https://

    server {
        listen          80 default_server;
        server_name     secure.example.com;

        rewrite ^ https://secure.example.com$request_uri? permanent;

        # dummy redirect, if http+https-server-in-one
        if ($scheme = http) {
            return 301 https://$server_name$request_uri;
        }

    }


    server {
        # turn on ssl + spdy
        listen          443 ssl spdy default_server;
        server_name     secure.example.com;

        # sending hsts-header / 12 months
        add_header  Strict-Transport-Security "max-age=31536000; includeSubDomains";

        # usually not needed
        #add_header  Alternate-Protocol  443:npn-spdy/2;

        # ssl-config

        ssl_certificate     /etc/ssl/secure.example.com.crt-combined;
        ssl_certificate_key /etc/ssl/secure.example.com.key;

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

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

        # turn off gzip to protect against BREACH / http://breachattack.com/
        gzip on;

        #
        # ssl cipher-suites
        #

        # nginx-default - kind of ok and working in usually any cases
        ssl_ciphers         HIGH:!aNULL:!MD5

        # nginx-default-for-static
        #ssl_ciphers RC4:HIGH:!aNULL:!MD5;

        # nginx mailinglist suggestion
        #ssl_ciphers HIGH:!SSLv2:!MEDIUM:!LOW:!EXP:!RC4:!DSS:!aNULL:@STRENGTH;


        # bare minimum for basic + BEAST-mitigation
        # grade A w/ ssllabs, but no PFS
        #ssl_ciphers         RC4:HIGH:!aNULL:!MD5;

        # suggestion from sslabs
        #ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;

        # suggestion from hasgeek.com
        #ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;

        # bare minimum for BEAST-mitigation + PFS
        #ssl_ciphers !aNULL:!LOW:!MD5:!EXP:RC4:AES256:3DES:AES128:SEED:CAMELLIA;



        # PFS and most secure ciphers (think about using TLS1.2 only)
        # suggestion from code-bear.com
        #ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:RC4-SHA;

        # PFS + BEAST-mitigation 
        # suggestion from hynek.me
        #ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:RC4-SHA;


        # fast and secure, BEAST-mitigation but no PFS?
        # suggestion from http://unhandledexpression.com
        #ssl_ciphers ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM;

        #
        # suggestion my mozilla-server-team
        #
        #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;


    }


}

Appendix

Perftesting Cipher-Suites

Server:

Config:

worker_processes 8;

events {
        worker_connections 3000;
        multi_accept on;
}

http {

    keepalive_timeout 65;
    keepalive_requests 100000;

    ...

    server {

      listen 80;
      listen 443 ssl;

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

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

      # various ciphers, see below
      # ssl_ciphers ....


      location /perftest/ {
        gzip off;
        expires off;
        access_log off;
        return 200;

      }


    }

}

Perf-Setup:

And the winner is ...

results from perftest

nginx default

ssl_ciphers HIGH:!aNULL:!MD5;

nginx mailinglist suggestion

ssl_ciphers HIGH:!SSLv2:!MEDIUM:!LOW:!EXP:!RC4:!DSS:!aNULL:@STRENGTH;

nginx-default-for-static

ssl_ciphers RC4:HIGH:!aNULL:!MD5;

SSLLabs.com - suggestion

ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;

bare minimum for BEAST-mitigation

ssl_ciphers !aNULL:!LOW:!MD5:!EXP:RC4:AES256:3DES:AES128:SEED:CAMELLIA;

hasgeek.com - suggestion

ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;

** unhandeledexception.com - suggestion

ssl_ciphers ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM

code-bearer.com - suggestion

ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:RC4-SHA;

hynek.me - suggestion

ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:RC4-SHA;

Credits

Changelog

License

This Guide is licensed as Creative Commons BY-SA and you are hereby granted the rights

Under the following conditions:


You code … we platform.