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

15

Node.js默认发送 TLS_EMPTY_RENEGOTIATION_INFO_SCSV 密码来保护自己免受 POODLE攻击

我试图通过覆盖TLS密码列表来避免发送此密码(即使这可能会带来安全风险)。

但是,无论我怎么做,Node.js都会继续发送 TLS_EMPTY_RENEGOTIATION_INFO_SCSV 密码。 我正在尝试故意避免发送此密码,以模仿Firefox / Chrome的TLS协商。

以下是我用于修改和检查Node正在发送哪些密码的代码:

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直接无关,而是与您正在使用的请求模块有关。或者您是否已将问题调试至node.js核心? - crackmigg
我不确定这是否正确:“如果我强制使用TLS 1.2(通过禁用协议降级),则发送此密码是不必要的。” 我认为所有版本的TLS都会受到降级攻击的影响,因为TLS不使用{min-TLS,max-TLS}版本对。相反,TLS_FALLBACK_SCS随着时间的推移而工作,因此它将应用于连续连接,而不是单个连接尝试中的真空。 - jww
@migg 它在 Node.js 核心中 -- 请查看 ssl_lib.c#L1472,这似乎是 Node.js 中添加 SCSV 密码的客户端 Hello 的位置(我可能对行数有所错误,但它在那个文件中)。request npm 模块依赖于 Node.js 的 tls 包,该包通过 openssl 处理 TLS 连接。@jww 你可能是正确的,它可能不安全,但是,我仍然想为测试用例禁用它,并且目前不关心安全性问题。 - Elad Nava
2个回答

4

考虑到这个问题与Node.js有关,有一种简单的方法可以处理您的问题,而不必深入研究它:

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

使用nginx的示例配置(在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;
   }
}

并将Node.js更改为:

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设置选项。
特别有趣的是SECURE RENEGOTIATION部分和以下选项:
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
允许在OpenSSL和未打补丁的客户端或服务器之间进行旧版不安全的重协商。有关详细信息,请参见SECURE RENEGOTIATION部分。
但我不确定这是否会防止发送重协商密码。如果此选项实际上是正确的,则可能有一种方法可以修补Node.js以使用该选项或重新编译带有该选项的OpenSSL。
当然也有使用旧未打补丁版本的选项。从我的理解来看,TLS_EMPTY_RENEGOTIATION_INFO_SCSV与POODLE无关,而是来自旧版本的修复:
实施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...或者使用未打补丁的OpenSSL和nginx。
这就是我卡住的地方。虽然不是完整的答案,但我认为至少值得分享。
总之,如果要在不重新编译的情况下执行此操作,请使用未打补丁的OpenSSL和nginx,并配置多个服务器,每个客户端一个。
如果您需要仅在node中完成此操作,最好的选择是直接补丁OpenSSL并重新编译node。

这是正确的方式。我总是让Nginx处理我的SSL——未来出现问题的风险要小得多。 - David Betz
非常感谢您详细的回答!我认为最终我会修补Node.js并手动编译它,因为我无法避免在node 0.8.x上发送此密码。 - Elad Nava

0

看起来TLS_EMPTY_RENEGOTIATION_INFO是一个占位符密码套件,执行与扩展“renegotiation_info”相同的功能。此外,似乎OpenSSL没有设置“renegotiation_info”扩展的方法,因此需要这个空密码套件。

来源:c-openssl-setting-list-of-ciphers
来源:RFC 5746 Section-3.3


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接