I'm currently using nginx with the following ciphers:

ssl_ciphers HIGH:!aNULL:!eNULL:!LOW:!ADH:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;

I would like to maintain compatibility to older browsers, especially also older mobile browsers and therefore not completely disallow SHA1.

How can I achieve that SHA256 is preferred over SHA1 for MAC (Message Authentication Code) and always used when possible.

I can i.e. force SHA256 to be applied by adding SHA256:!SHA: to my ssl_ciphers string but this would also disallow SHA1 completely.

With the ssl_cipher at the beginning it tends however to just use SHA1. Any recommendations?

Update 29.12.2014

Thanks everybody for the constructive inputs and discussion.

Even though I still think that the Mozilla page on Server side TLS overall covers the topic quite good - I would only recommend the Modern compatibility with the limitation that the DSS ciphers should be removed from it and explicitly disallowed (!DSS) as recommended in the comment by Anti-weakpasswords - thanks for spotting it.


Interestingly ssllabs did not alert or down rate for this...

Further I prefer to use custom generated Diffie-Hellman parameters. Even though the standard ones are obviously considered safe. What are the OpenSSL standard Diffie-Hellman parameters (primes)?

openssl dhparam -check -out /etc/ssl/private/dhparams.pem 2048

increase that to 4096 for paranoia and fun if you like.

  • 1
    Re update4: the full cipherstrings are not in the three examples at #Nginx, but they are near the top of the page, and somes conversions to not-(wholly-)OpenSSL forms near the bottom. The generator page covers a narrower range, but is convenient within that range. Commented Dec 15, 2014 at 9:20
  • True, didn't notice that. Thanks for pointing it out. Commented Dec 16, 2014 at 21:21
  • 2
    Re: Update 16.12.2014: I would strongly suggest at minimum removing the -DSS- ciphers and adding !DSS to that string; DSS ciphers tend to be limited to too-small 1024 bit key sizes. See https://www.ssllabs.com/ssltest/viewClient.html?name=IE&version=11&platform=Win%208.1, cipher suite list, superscript note 2, "(2) Cannot be used for Forward Secrecy because they require DSA keys, which are effectively limited to 1024 bits." Commented Dec 28, 2014 at 20:05
  • Thanks for the sharp eyes! No idea why Mozilla added DSS it was even not included in the standard nginx setting. Interestingly ssllabs checks didn't complain or rate it down. I'll update the post. Commented Dec 29, 2014 at 18:49

7 Answers 7


First, let's go over how cipher suite negotiation works, very briefly. For example, we can use the TLS 1.2 document RFC 5246 starting at section to see, in the short short form:

  • ClientHello: The client tells the server which cipher suites the client supports
  • Now the server picks one
  • I'll discuss how to control which one it picks next!
  • ServerHello: The server tells the client which cipher suite it has chosen, or gives the client a failure message.

Now, as to the actual selection. I've used the nginx ssl module documentation, the Qualys 2013 article on Configuring Apache, Nginx, and OpenSSL for Forward Secrecy, and the Hynek Hardening Your Web Server’s SSL Ciphers article for reference. The latter two cover both Apache and Nginx (as both use OpenSSL as a base).

Essentially, you need to tell Nginx to use the order you select, and you need to select an order. To see what the results of that order would be, you can use the OpenSSL command line, e.g.


NOTE: You may want to remove :!3DES from that string; 3-key triple-DES isn't efficient, but it is still secure in and of itself to more or less 112 bits of security, and is very, very common.

Use the above command to determine which cipher suites will be most preferred and least preferred in your configuration, and change it until you like the results. The references I've given have their own strings; I amended it slightly to get the above example (removing RC4 and SEED, and putting every TLS 1.2 cipher suite above any 'SSLv3' cipher suite, for example).

Then, for Nginx in particular, you would alter your configuration file to include something like:

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

Add in SSLv3 to ssl_protocols if you really insist on it.

The ssl_prefer_server_ciphers will inform nginx to use the order we specify, and ignore the order the client presents their cipher list in. Now, if the only shared cipher suite between the ClientHello and the list OpenSSL ciphers -v ... gives is our least preferred cipher, that's of course what nginx will use. If nothing matches, then we send the client a failure notice.

The ssl_ciphers command is the meat of the choice, here, as nginx will inform OpenSSL of our preferred cipher suite list. Please, please use the openssl ciphers -v command to see the results you get on your platform. Ideally, check it again after changing OpenSSL versions.

Also, please read Scott Helme's article on Setting up HSTS (HTTP Strict Transport Security) in nginx, which will allows a host to enforce the use of HTTPS on the client side. Be sure to include the HSTS header inside the http block with the ssl listen statement.

Edited to add: At least after this (if not before also), go to Qualys SSL Labs to see HTTPS security information and to Test Your Server that's been kept pretty well up to date for the last few years. Recommendations change regularly, and sometimes even frequently reverse themselves (RC4, for example, what nearly whiplash inducing). You can also even Test Your Browser!

  • Thanks openssl -v ciphers ... is exatcly what I needed. Commented Apr 2, 2014 at 17:40
  • You're welcome; see also the Qualys SSL Labs in the new last paragraph. I'm curious - why forbid Camellia? It's an equivalent block cipher to AES, officially endorsed by the EU and Japan, per the results of the NESSIE and CRYPTREC competitions, respectively. Commented Apr 3, 2014 at 6:11
  • Good point, I just copied that from the cloudlfare ciphers. I see no additional benefit though when allowing it and retesting on cloudflare. It seems not to be FS capable? I'm really not a cipher algorithm expert though. Commented Apr 3, 2014 at 7:20
  • 1
    Forward secrecy is an attribute of having an ephemeral key in the mix (the last "E" in "DHE" or "ECDHE", for example); it has nothing to do with the choice of symmetric cipher as such. Quite a lot of the ciphers my OpenSSL install shows for your currently chosen list don't have forward secrecy, like AES128-GCM-SHA256 (third most preferred on your list). ECDHE-RSA-AES128-GCM-SHA256, of course, does offer forward secrecy. Commented Apr 3, 2014 at 7:34
  • 2
    @binaryanomaly TLS 1.2 includes the full set of modern Camellia cipher suites, PFS and otherwise. Unfortunately, OpenSSL doesn't. OpenSSL does support the older ones like DHE-RSA-CAMELLIA128-SHA, but not the newer ECDHE or ECDSA ones. Commented Apr 4, 2014 at 1:02

Mozilla has an online tool that will help you choose the correct cipher suite.


It will let you input your server version, software version, etc. and then choose between a balance of security and legacy support.

  • Read the question including the update again and you'll see that this information is already contained. Further Mozilla recommendation is soso. Commented Apr 22, 2015 at 10:39
  • @binaranomaly I read the update. It links to the mozilla wiki but my understanding is that the tool I linked to is better because it is kept up to date by taking your server version and other parameters as input
    – Alex W
    Commented Apr 22, 2015 at 12:36
  • 3
    very nice tool without need to read all the pitfalls, you only need to know what are you using
    – tyoc213
    Commented Nov 26, 2015 at 23:34
  • This is an excellent tool that yields great results! Commented Dec 15, 2018 at 6:48

OpenSSL naturally will prefer newer MACs for otherwise-equivalent cipher suites. For example, the lengthy openssl ciphers -v output for your cipher string starts with:

ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2  Kx=ECDH        Au=RSA    Enc=AESGCM(256)    Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2  Kx=ECDH        Au=ECDSA  Enc=AESGCM(256)    Mac=AEAD
ECDHE-RSA-AES256-SHA384        TLSv1.2  Kx=ECDH        Au=RSA    Enc=AES(256)       Mac=SHA384
ECDHE-ECDSA-AES256-SHA384      TLSv1.2  Kx=ECDH        Au=ECDSA  Enc=AES(256)       Mac=SHA384
ECDHE-RSA-AES256-SHA           SSLv3    Kx=ECDH        Au=RSA    Enc=AES(256)       Mac=SHA1
ECDHE-ECDSA-AES256-SHA         SSLv3    Kx=ECDH        Au=ECDSA  Enc=AES(256)       Mac=SHA1

Of course, TLS will only use cipher suites supported mutually by both the server and client, and neither Chrome nor Firefox support HMAC-SHA256 cipher suites. Since HMAC-SHA1 (and even HMAC-MD5) are still considered secure, I believe their developers (and those of NSS, the TLS library they both use) are skeptical of wasting developer effort and TLS handshake size adding new, unnecessary, and backwards-incompatible cipher suites.

Look at, for example, Chrome 33's supported cipher suites in order of preference:

  1. ChaCha20-Poly1305,
  2. AES-128-GCM,
  3. AES-256-CBC with HMAC-SHA1,
  4. RC4 (ugh) and AES-128-CBC with HMAC-SHA1, ...

OpenSSL doesn't support ChaCha20-Poly1305. If yours doesn't support AES-GCM either (???) and uses an RSA certificate, ECDHE-RSA-AES256-SHA is naturally the cipher suite Chrome will use. (Firefox 29 would use ECDHE-RSA-AES128-SHA.)

(The "SHA-256" cipher suites you've seen being used on other websites are presumably ChaCha20-Poly1305 or AES-128-GCM, which are AEADs that do not make use of HMAC, but whose cipher suites use SHA-256 in the PRF.)


for best compatibility the cloudflare-cipher-suite is not the best; i found the following better:

# suggestion from sslabs / including PFS, good compatibility

# suggestion my mozilla-server-team - good compatibility, pfs

when you check each setup with ssllabs you'll find for those 2 suites the following statement:

  • Forward Secrecy Yes (with most browsers) ROBUST

while on your suggested cipher_suite it says:

  • Forward Secrecy Yes (with modern browsers)

additional information: Guide to Nginx + SSL + SPDY

  • Thanks for the info. The mozilla recommendation looks best to me, less RC4 use with that ciphers. Commented Apr 4, 2014 at 19:18
  • 1
    For what it's worth, Mozilla offers a second configuration string farther down the page, in the "RC4 Weaknesses" section, that doesn't use RC4 at all. For IE/XP compatibility it instead uses 3DES, which is slow but actually more or less secure. Commented Apr 5, 2014 at 4:59
  • @MattNordhoff: thanxs for that addition; from the docs: "While 3DES provides more resistant cryptography, it is also 30 times slower and more cpu intensive than RC4." i must say, <rant>, i'd give a sh*t on someones security, if he/she is using a browser like ie 6/7, if this leads to a massive impact on performance </rant> Commented Apr 5, 2014 at 9:30
  • In the mozilla ciphers the only thing the RC4 strings are for is for IE8/XP support according to the output of the qualys test. Unfortunately still a far too common (corporate) setup. In that case RC4 can be an ok compromise as IE8/XP is performance wise already a pain and my site is not security critical at all. Commented Apr 6, 2014 at 22:04
  • Note that this configuration is not secure anymore, since it enables TLS_ECDHE_RSA_WITH_RC4_128_SHA and TLS_RSA_WITH_RC4_128_SHA.
    – mbomb007
    Commented Nov 5, 2019 at 22:14

Comodo recommendation is:


Source: https://support.comodo.com/index.php?/Default/Knowledgebase/Article/View/789/37/


https://cipherli.st/ is another site that offers:

The above ciphers are Copy Pastable in your nginx, Lighttpd or Apache config. These provide Strong SSL Security for all modern browsers, plus you get an A+ on the SSL Labs Test.

This stuff goes out of date all the time, but for what it's worth, in May 2018 here's its recommendations for nginx:

ssl_protocols TLSv1.3;# Requires nginx >= 1.13.0 else use TLSv1.2
ssl_prefer_server_ciphers on; 
ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7

Choice of hash function (SHA-1 vs SHA-256) does not really depend on the cipher suite, but on the protocol version. Basically, you get SHA-256 if you use TLS 1.2, SHA-1 if you use an older version.

(Yes, I known this is a simplified description of a slightly more complex situation, but here it works.)

Normally, client and server will use the highest protocol version that they both support, so you should already get TLS-1.2 (hence SHA-256) whenever it is possible. Note that this requires that both the server's code (OpenSSL) and the client's code are recent. You can alter that mechanism explicitly with ssl_protocols.

  • Well server side I have ssl_protocols TLSv1 TLSv1.1 TLSv1.2; And I use Firefox 29 which should be TLS 1.2 capable, so why do I end up with SHA1? Commented Apr 1, 2014 at 18:42
  • I might have to add that on other sites I am able to use SHA256 so it cannot the browser? Commented Apr 1, 2014 at 18:48
  • Chrome actually says it's TLS 1.2 with SHA1? The connection uses TLS 1.2. The connection is encrypted using AES_256_CBC, with SHA1 for message authentication and ECDHE_RSA as the key exchange mechanism. Commented Apr 1, 2014 at 18:52
  • 1
    Sorry, but no. The PRF hash depends on the version, but the HMAC hash (still) depends on the suite. To be exact, rfc5246 specifies the PRF for all pre-existing suites (now) uses SHA-256, and the PRF for new suites is defined per suite (as well as HMAC if used), and all new suites to date define SHA-256 or SHA-384. It would be possible to define a new suite using PRF (and/or HMAC) SHA-1 or even MD5, but it would be crazy; what will probably make sense soon are some suites using SHA-3. Commented Dec 30, 2014 at 9:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .