How to force Nodejs v19+ to use TLS 1.2 to avoid write EPROTO SSL routines:ssl3_read_bytes:sslv3 alert handshake failure…SSL alert number 40

huangapple go评论85阅读模式
英文:

How to force Nodejs v19+ to use TLS 1.2 to avoid write EPROTO SSL routines:ssl3_read_bytes:sslv3 alert handshake failure...SSL alert number 40

问题

I am trying to get NodeJs to make get requests to a site that has disabled TLS 1.3. However, each request I make throws a handshake exception like the following:

Error: write EPROTO 00683890CA7F0000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1605:SSL alert number 40

However, if I downgrade to NodeJs v16.20.0, the request succeeds.

You can see that the site in question has disabled TLS 1.3:

https://www.ssllabs.com/ssltest/analyze.html?d=www.legislation.gov.au&s=54.66.220.183

I have used printed the ciphers available in both v19 and v16 (using tls.getCiphers()) and have confirmed that the list of available ciphers is the same in both versions.

However, I have tried various permutations of setting the min and max TLS versions, creating httpsAgents, setting ciphers to use (both as a list and as 'SECLEVEL=1'), as well as trying the Node https client, axios and got, but so far, all to no avail.

Here is an example attempt to request the URL that fails in v19 but succeeds in v16:

const https = require('https');
var options = {
    hostname: 'www.legislation.gov.au',
    port: 443,
    path: '/',
    minVersion: "TLSv1.2",
    maxVersion: "TLSv1.2"
};

https.get(options, response => {
    let body = '';
    response.on('data', d => {
        body += d;
    });
    response.on('end', () => {
        console.log(body);
    });
}).on('error', err => {
    console.error(err);
});

I would appreciate any advice that anyone may be able to provide, especially if they can provide a working sample of the request above.

英文:

I am trying to get NodeJs to make get requests to a site that has disabled TLS 1.3. However, each request I make throws a handshake exception like the following:

Error: write EPROTO 00683890CA7F0000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1605:SSL alert number 40

However, if I downgrade to NodeJs v16.20.0, the request succeeds.

You can see that the site in question has disabled TLS 1.3:

https://www.ssllabs.com/ssltest/analyze.html?d=www.legislation.gov.au&s=54.66.220.183

I have used printed the ciphers available in both v19 and v16 (using tls.getCiphers()) and have confirmed that the list of available ciphers is the same in both versions.

However, I have tried various permutations of setting the min and max TLS versions, creating httpsAgents, setting ciphers to use (both as a list and as '@SECLEVEL=1'), as well as trying the Node https client, axios and got, but so far, all to no avail.

Here is an example attempt to request the URL that fails in v19 but succeeds in v16:

const https = require('https');
var options = {
    hostname: 'www.legislation.gov.au',
    port: 443,
    path: '/',
    minVersion: "TLSv1.2",
    maxVersion: "TLSv1.2"
};

https.get(options, response => {
        let body = '';
        response.on('data', d => {
                body += d;
        });
        response.on('end', () => {
                console.log(body);
        });
}).on('error', err => {
        console.error(err);
});

I would appreciate any advice that anyone may be able to provide, especially if they can provide a working sample of the request above.

答案1

得分: 2

尝试使用ciphers: 'DEFAULT:@SECLEVEL=0'

首先,我能够在docker-alpine映像中(这些映像仅稳定)使用v18.16.0与v16.20.0复现此问题。

其次,问题并非由服务器的版本不兼容引起。v16和v18默认都提供1.3版本,并且服务器在不拒绝的情况下按照RFC正确地协商到1.2版本。此外,命令行的openssl和curl也默认提供1.3版本,并且可以成功连接,但请参阅下文。服务器自己标识为IIS/8.5,这是十年前的版本,通常只运行在同样古老的Windows上(即8.1/2012),这些Windows根本不支持1.3版本,所以它可能不是“禁用”,只是不存在。

我只发现v16和v18之间(以及命令行OpenSSL 1.1.1和3.0.x之间)的ClientHello中有两个不同之处:supported_groups包括FFDHE组,而sigalgs不包括SHA1方案。似乎后者是关键;如果我配置ciphers:'DEFAULT:@SECLEVEL=0'(或使用等效的命令行选项),SHA1签名会被添加回去,握手成功进行——尽管从正规角度来看,SHA1应该在SECLEVEL=1时才合格,而且服务器选择了一个使用RSA密钥交换且根本不使用任何签名的套件。

另外,需要注意的是:我的研究耽搁了一段时间,因为某些我的测试系统首选的IPv6地址似乎连接到一个完全不同的服务器,它的响应方式完全不同,尽管它也在AWS上,并且根据给定的名称来看似乎是一个ELB。

英文:

Try ciphers: 'DEFAULT:@SECLEVEL=0'

First, I was able to reproduce with v18.16.0 vs v16.20.0 both in docker -alpine images (which are stable only).

Second, the problem is not version intolerance by the server. Both v16 and v18 offer 1.3 by default, and the server negotiates to 1.2 correctly as per RFCs when it doesn't reject. Moreover commandline openssl and curl also offer 1.3 by default and succeed -- but see below. The server identifies itself as IIS/8.5 which is ten years old, and normally runs only on equally old Windows (i.e. 8.1/2012), which didn't support 1.3 at all, so it's probably not 'disabled' just nonexistent.

I find only two differences in the ClientHello between v16 and v18 (and between commandline OpenSSL 1.1.1 and 3.0.x): supported_groups includes the FFDHE groups and sigalgs does NOT include SHA1 schemes.
It appears the latter is the one that matters; if I configure ciphers:'DEFAULT:@SECLEVEL=0' (or use commandline equivalent) the SHA1 signatures are added back in, and the handshake succeeds -- even though SHA1 nominally ought to qualify at SECLEVEL=1, plus the server chooses a suite with RSA key exchange which doesn't use ANY signature at all.

Also, a warning: my investigations were delayed quite a bit because the IPv6 addresses, which some of my test systems preferred, apparently go to a quite different server which responds very differently, although also in AWS and apparently an ELB from the name given.

huangapple
  • 本文由 发表于 2023年6月8日 20:58:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76432102.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定