Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid sending TLS_EMPTY_RENEGOTIATION_INFO_SCSV cipher in TLS Client Hello

Node.js sends the TLS_EMPTY_RENEGOTIATION_INFO_SCSV cipher by default to protect itself against the POODLE attack.

I'm trying to avoid sending this cipher (even though this may pose a security risk) by overriding the TLS ciphers with a custom list of ciphers.

However, Node.js keeps sending the TLS_EMPTY_RENEGOTIATION_INFO_SCSV cipher no matter what I do. I'm trying to deliberately avoid sending this cipher to mimic the TLS negotiation of Firefox/Chrome.

Here's the code I use to modify and check which ciphers Node is sending:

var request = require('request');

var ciphers = [
    'ECDHE-ECDSA-AES128-GCM-SHA256',
    'ECDHE-RSA-AES128-GCM-SHA256',
    'ECDHE-ECDSA-AES256-SHA',
    'ECDHE-ECDSA-AES128-SHA',
    'ECDHE-RSA-AES128-SHA',
    'ECDHE-RSA-AES256-SHA',
    'DHE-RSA-AES128-SHA',
    'DHE-RSA-AES256-SHA',
    'AES128-SHA',
    'AES256-SHA',
    'DES-CBC3-SHA'
].join(':');

var options = {
    ciphers: ciphers,
    secureProtocol: 'TLSv1_2_method',
    url: 'https://www.howsmyssl.com/a/check'
};

request(options, function (error, response, body){
    if (!error) {
        console.log(body);
    }
    else {
        console.log(error);
    }
});

Is there any way to disable sending this cipher in Node.js?

like image 918
Elad Nava Avatar asked Feb 07 '16 14:02

Elad Nava


Video Answer


1 Answers

Given that this issue is related to Node.js, there is one simple method to deal with your issue without actually digging to much into it:

Put a web proxy in front of your Node.js process and let it handle the complete SSL connection. In the Node.js code itself, you would only send a request to a local HTTP server.

Example configuration with nginx (inside the http directive):

server {
   listen 8080;
   location / {
      resolver 8.8.8.8;
      proxy_pass https://www.howsmyssl.com$uri$is_args&args;
      proxy_ssl_protocols TLSv1.2;
      proxy_ssl_ciphers AESGCM:!aNULL;
   }
}

And change the nodejs to:

var request = require('request');

var options = {
    url: 'http://localhost:8080/a/check'
};

request(options, function (error, response, body){
    if (!error) {
        console.log(body);
    }
    else {
        console.log(error);
    }
});

Unfortunately though I actually did this, and the result was the same:

{"given_cipher_suites":["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_DH_DSS_WITH_AES_256_GCM_SHA384","TLS_DHE_DSS_WITH_AES_256_GCM_SHA384","TLS_DH_RSA_WITH_AES_256_GCM_SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_DH_DSS_WITH_AES_128_GCM_SHA256","TLS_DHE_DSS_WITH_AES_128_GCM_SHA256","TLS_DH_RSA_WITH_AES_128_GCM_SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_EMPTY_RENEGOTIATION_INFO_SCSV"],"ephemeral_keys_supported":true,"session_ticket_supported":true,"tls_compression_supported":false,"unknown_cipher_suite_supported":false,"beast_vuln":false,"able_to_detect_n_minus_one_splitting":false,"insecure_cipher_suites":{},"tls_version":"TLS 1.2","rating":"Probably Okay"}

This basically means that its probably standard OpenSSL behavior.

There are options which can be set in OpenSSL using SSL_CTX_set_options

Especially interesting here is the SECURE RENEGOTIATION section and this option:

SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION

Allow legacy insecure renegotiation between OpenSSL and unpatched clients or servers. See the SECURE RENEGOTIATION section for more details.

I am not certain though if this actually prevents the renegotiation cipher from being send. If this option is actually correct, there might be a way to either patch Node.js to use that option or recompile OpenSSL with that option.

There would of course also be the option to use an old unpatched version. From my understanding though TLS_EMPTY_RENEGOTIATION_INFO_SCSV is not related to POODLE, but from an older fix:

CVE-2009-3555 (OpenSSL advisory) 5th November 2009:
Implement RFC5746 to address vulnerabilities in SSL/TLS renegotiation. Fixed in OpenSSL 0.9.8m (Affected 0.9.8l, 0.9.8k, 0.9.8j, 0.9.8i, 0.9.8h, 0.9.8g, 0.9.8f, 0.9.8e, 0.9.8d, 0.9.8c, 0.9.8b, 0.9.8a, 0.9.8)

Modern Node.js comes with a statically linked OpenSSL however and does not support OpenSSL 0.9.8, so you would need an older version of Node.js regardless... or use the nginx stuff with an unpatched OpenSSL...

This is kind of where I am stuck. Its not really an complete answer, but I think its at least worth to share.

To sum it up though, I think if you want to do this without recompiling use nginx with and unpatched OpenSSL, and configure multiple servers, one for each client you want to mimic.

If you require this to be soley done in node, your best bet is to patch OpenSSL there directly and recompile node.

like image 186
Nappy Avatar answered Nov 05 '22 08:11

Nappy