From 1b1fe536557184731123c1054a0b6146737d0ed7 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 30 Mar 2015 09:56:01 -0700 Subject: [PATCH] tls: more secure defaults Port of io.js commit: https://github.com/iojs/io.js/commit/77f35861d0217273b9e478f5d35bd7d8e47 Original commit message: This updates the default cipher suite to an more secure list, which prefers strong ciphers with Forward Secrecy. Additionally, it enables `honorCipherOrder` by default. Noteable effect of this change is that the insecure RC4 ciphers are disabled and that Chrome negotiates a more secure ECDHE cipher. Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny PR-URL: https://github.com/iojs/io.js/pull/826 --- doc/api/tls.markdown | 44 +++++++++++++------------------ lib/_tls_wrap.js | 6 ++--- lib/tls.js | 23 ++++++++++++---- test/simple/test-tls-dhe.js | 1 + test/simple/test-tls-getcipher.js | 2 +- 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index 410d88300c8e..ab4656a9eedc 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -25,8 +25,10 @@ To create a self-signed certificate with the CSR, do this: Alternatively you can send the CSR to a Certificate Authority for signing. -(TODO: docs on creating a CA, for now interested users should just look at -`test/fixtures/keys/Makefile` in the Node source code) +For Perfect Forward Secrecy, it is required to generate Diffie-Hellman +parameters: + + openssl dhparam -outform PEM -out dhparam.pem 2048 To create .pfx or .p12, do this: @@ -170,31 +172,20 @@ automatically set as a listener for the [secureConnection][] event. The - `crl` : Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List) - - `ciphers`: A string describing the ciphers to use or exclude. - - To mitigate [BEAST attacks] it is recommended that you use this option in - conjunction with the `honorCipherOrder` option described below to - prioritize the non-CBC cipher. - - Defaults to - `ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL`. - Consult the [OpenSSL cipher list format documentation] for details - on the format. - - `ECDHE-RSA-AES128-SHA256`, `DHE-RSA-AES128-SHA256` and - `AES128-GCM-SHA256` are TLS v1.2 ciphers and used when node.js is - linked against OpenSSL 1.0.1 or newer, such as the bundled version - of OpenSSL. Note that it is still possible for a TLS v1.2 client - to negotiate a weaker cipher unless `honorCipherOrder` is enabled. + - `ciphers`: A string describing the ciphers to use or exclude, separated by + `:`. The default cipher suite is: - `RC4` is used as a fallback for clients that speak on older version of - the TLS protocol. `RC4` has in recent years come under suspicion and - should be considered compromised for anything that is truly sensitive. - It is speculated that state-level actors possess the ability to break it. + ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256: + DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256: + HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA - **NOTE**: Previous revisions of this section suggested `AES256-SHA` as an - acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore - susceptible to [BEAST attacks]. Do *not* use it. + The default cipher suite prefers ECDHE and DHE ciphers for Perfect Forward + secrecy, while offering *some* backward compatibility. Old clients which + rely on insecure and deprecated RC4 or DES-based ciphers (like Internet + Explorer 6) aren't able to complete the handshake with the default + configuration. If you absolutely must support these clients, the + [TLS recommendations] may offer a compatible cipher suite. For more details + on the format, see the [OpenSSL cipher list format documentation]. - `ecdhCurve`: A string describing a named curve to use for ECDH key agreement or false to disable ECDH. @@ -212,7 +203,7 @@ automatically set as a listener for the [secureConnection][] event. The times out. - `honorCipherOrder` : When choosing a cipher, use the server's preferences - instead of the client preferences. + instead of the client preferences. Default: `true`. Although, this option is disabled by default, it is *recommended* that you use this option in conjunction with the `ciphers` option to mitigate @@ -853,5 +844,6 @@ The numeric representation of the local port. [ECDHE]: https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman [asn1.js]: http://npmjs.org/package/asn1.js [OCSP request]: http://en.wikipedia.org/wiki/OCSP_stapling +[TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS [SSL_CTX_set_options]: https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html [CVE-2014-3566]: https://access.redhat.com/articles/1232123 diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index f4ee762eed4d..378f6053278c 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -735,10 +735,10 @@ Server.prototype.setOptions = function(options) { secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE; } - if (options.honorCipherOrder) - this.honorCipherOrder = true; + if (options.honorCipherOrder !== undefined) + this.honorCipherOrder = !!options.honorCipherOrder; else - this.honorCipherOrder = false; + this.honorCipherOrder = true; this.secureOptions = secureOptions; diff --git a/lib/tls.js b/lib/tls.js index 7aad494b1e0d..58f80bba8b12 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -35,11 +35,24 @@ exports.CLIENT_RENEG_WINDOW = 600; exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024; -exports.DEFAULT_CIPHERS = - // TLS 1.2 - 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' + - // TLS 1.0 - 'RC4:HIGH:!MD5:!aNULL'; +exports.DEFAULT_CIPHERS = [ + 'ECDHE-RSA-AES256-SHA384', + 'DHE-RSA-AES256-SHA384', + 'ECDHE-RSA-AES256-SHA256', + 'DHE-RSA-AES256-SHA256', + 'ECDHE-RSA-AES128-SHA256', + 'DHE-RSA-AES128-SHA256', + 'HIGH', + '!aNULL', + '!eNULL', + '!EXPORT', + '!DES', + '!RC4', + '!MD5', + '!PSK', + '!SRP', + '!CAMELLIA' +].join(':'); exports.DEFAULT_ECDH_CURVE = 'prime256v1'; diff --git a/test/simple/test-tls-dhe.js b/test/simple/test-tls-dhe.js index 3975c5ed40a3..8844f8527998 100644 --- a/test/simple/test-tls-dhe.js +++ b/test/simple/test-tls-dhe.js @@ -47,6 +47,7 @@ function test(keylen, expectedCipher, cb) { var options = { key: key, cert: cert, + ciphers: ciphers, dhparam: loadDHParam(keylen) }; diff --git a/test/simple/test-tls-getcipher.js b/test/simple/test-tls-getcipher.js index 22a280e58743..8fb9d528731d 100644 --- a/test/simple/test-tls-getcipher.js +++ b/test/simple/test-tls-getcipher.js @@ -49,7 +49,7 @@ server.listen(common.PORT, '127.0.0.1', function() { rejectUnauthorized: false }, function() { var cipher = client.getCipher(); - assert.equal(cipher.name, cipher_list[0]); + assert.equal(cipher.name, cipher_list[1]); assert(cipher_version_pattern.test(cipher.version)); client.end(); server.close();