避免在TLS客户端中发送TLS_EMPTY_RENEGOTIATION_INFO_SCSV密码Hello

Node.js默认发送TLS_EMPTY_RENEGOTIATION_INFO_SCSV密码,以防止POODLE攻击 。

我试图通过用自定义密码列表覆盖TLS密码来避免发送这种密码(尽pipe这可能构成安全风险)。

但是,无论我做什么,Node.js都会一直发送TLS_EMPTY_RENEGOTIATION_INFO_SCSV密码。 我试图故意避免发送这个密码来模仿Firefox / Chrome的TLS协商。

这里是我用来修改和检查哪些密码节点发送的代码:

 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); } }); 

有什么办法可以禁止在Node.js中发送这个密码吗?

鉴于这个问题与Node.js有关,有一个简单的方法可以解决你的问题,而不需要深入研究:

将一个Web代理放在Node.js进程前面,让它处理完整的SSL连接。 在Node.js代码本身中,您只会向本地HTTP服务器发送请求。

nginxconfiguration示例(在http指令中):

 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; } } 

并将nodejs更改为:

 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); } }); 

不幸的是,虽然我真的这样做,结果是一样的:

 {"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"} 

这基本上意味着它可能是标准的OpenSSL行为。

有些选项可以使用SSL_CTX_set_options在OpenSSL中设置

这里特别有趣的是SECURE RENEGOTIATION部分和这个选项:

SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION

允许OpenSSL和未修补的客户端或服务器之间的传统不安全的重新协商。 有关更多详细信息,请参阅“安全重置”部分。

如果这实际上阻止了重新协商密码的发送,我不确定。 如果这个选项实际上是正确的,那么可以通过修补Node.js来使用该选项,或者使用该选项重新编译OpenSSL。

当然也可以select使用旧的未打补丁版本。 从我的理解,虽然TLS_EMPTY_RENEGOTIATION_INFO_SCSV是不相关的POODLE,但从一个较早的修复:

CVE-2009-3555(OpenSSL咨询)2009年11月5日:
实施RFC5746来解决SSL / TLS重新协商中的漏洞。 固定在OpenSSL 0.9.8m(影响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)

现代的Node.js带有一个静态链接的OpenSSL,但是不支持OpenSSL 0.9.8,所以你需要一个老版本的Node.js,不pipe…或者把nginx的东西用在一个未打补丁的OpenSSL上。

这是我卡住的地方。 这不是一个完整的答案,但我认为它至less值得分享。

总结一下,我想如果你想这样做,而不重新编译使用nginx和未打补丁的OpenSSL,并configuration多个服务器,为每个客户端模拟一个。

如果你需要在节点上完成这个任务,最好的办法就是直接修补OpenSSL并重新编译节点。