Disabling SSLv2 with Node.js

It recently came to light that SSLv2 support in the TLS/HTTPS modules in node.js is enabled by default if supported by the system OpenSSL library. Now, it may or may not be a suprise to some that SSLv2 is sufficiently broken and has in fact has been deprecated (since 1996) that it warrants disabling in any serious production environment.

As of OpenSSL v1.0+ it is diabled by default, as evident in newer versions of Debian and Ubuntu since 10.04.

Now, for node.js depending on the SSL library used, it will enable SSLv2 by default , which as you know by know is not a good idea.

To verify that you cannot connect with SSLv2 to your node server, fire off the following openssl command:

$ openssl s_client -connect hostname:443 -ssl2

And the response should look something akin to:

CONNECTED(00000003)
83295:error:1407F0E5:SSL routines:SSL2_WRITE:ssl handshake failure:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/ssl/s2_pkt.c:428:

If you see something like the following, then you should consider disabling SSLv2:

CONNECTED(00000003)
..

SSL handshake has read 736 bytes and written 434 bytes

One (seemingly undocumented on the server side) is to pass one of the available OpenSSL CTX methods such as SSLv3_method to the httpsOptions object in the TLS/HTTPS .createServer(...)methods in Node.js.

Setting this option will force a single protocol to the SSL handshake, meaning that for some older clients such as the default OpenSSL on OSX this will cause an issue for the handshake, where it tries to negotiate a SSLv23_method, which with the above change is an unsupported fallback method for SSLv2 ( note the SSL23_WRITE ), as per OSX 10.7:

○ openssl version
OpenSSL 0.9.8x 10 May 2012

○ openssl s_client -connect hostname:443
CONNECTED(00000003)
60349:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/ssl/s23_lib.c:182:

A solution for this particular problem which may affect applications that use the system OpenSSL on is to recompile node with the --no-ssl2 option.

After passing that option as ./configure --no-sslv2, you should find that older clients are now able to connect directly using TLSv1/SSLv3, and avoid the instant handshake fail as before:

 openssl s_client -connect stacka.to:443

CONNECTED(00000003)
depth=2 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA

..snip..

SSL-Session:
    Protocol  : TLSv1
    Cipher    : RC4-SHA
    Session-ID: 7B78B50B595C19AF3DA7BE845D0724C7F969505CEDDB3EA799E09C18A83433AB
    Session-ID-ctx: 
    Master-Key: EA61C4401AEA8057690E36D45B5101CBA970820A89F8A1D1AFF159578D14C39935B844BC8DA5A65E6970250F9D43D270
    Key-Arg   : None
    Start Time: 1372659259
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

If you have Nginx/Apache in front of Node.js then since v1.0 then make sure you're disabling it there too: http://www.evanhoffman.com/evan/2011/09/20/making-sure-sslv2-is-disabled-in-apache/

Note that on some popular SSL strength/vulnerability analysers, SSlv2 support is an automatically failing grade. By disabling it, you can go from an 'F' to a 'A' with a minor tweak!