如何让Node.js v19+强制使用TLS 1.2解决SSL握手失败错误?
Node.js v19+ 向禁用TLS 1.3的网站请求时握手失败的解决方案
问题重现
使用Node.js v19及以上版本向www.legislation.gov.au发起HTTPS请求时,抛出握手异常:
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
降级到Node.js v16.20.0后请求正常执行。已确认目标网站禁用TLS 1.3,且v19与v16的可用加密套件列表一致,尝试过锁定TLS版本、自定义Agent、指定加密套件等方法均无效。
失败的请求代码:
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); });
原因分析
Node.js v17+ 默认升级了OpenSSL版本,且默认安全级别从SECLEVEL=1提升到SECLEVEL=2。更高的安全级别会过滤掉部分旧版服务器支持的签名算法或证书配置,即便已锁定TLS 1.2版本,握手时仍会因安全策略不兼容被服务器拒绝。
可运行的解决方案代码
方案1:锁定TLS版本+降低安全级别
const https = require('https'); const constants = require('constants'); const options = { hostname: 'www.legislation.gov.au', port: 443, path: '/', minVersion: 'TLSv1.2', maxVersion: 'TLSv1.2', // 明确禁用TLS 1.3,避免握手时发送相关扩展 secureOptions: constants.SSL_OP_NO_TLSv1_3, // 降低OpenSSL安全级别到1,兼容旧服务器配置 ciphers: `${require('tls').DEFAULT_CIPHERS}@SECLEVEL=1` }; https.get(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => console.log(data)); }).on('error', err => console.error(err));
方案2:自定义HTTPS Agent(适合批量请求复用连接)
const https = require('https'); const constants = require('constants'); // 创建全局复用的Agent,确保所有请求使用相同的TLS配置 const tls12Agent = new https.Agent({ minVersion: 'TLSv1.2', maxVersion: 'TLSv1.2', secureOptions: constants.SSL_OP_NO_TLSv1_3, ciphers: `${require('tls').DEFAULT_CIPHERS}@SECLEVEL=1` }); const options = { hostname: 'www.legislation.gov.au', port: 443, path: '/', agent: tls12Agent }; https.get(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => console.log(data)); }).on('error', err => console.error(err));
关键配置说明
secureOptions: constants.SSL_OP_NO_TLSv1_3:强制禁用TLS 1.3,防止握手时向服务器发送TLS 1.3相关扩展字段,避免服务器因不支持而拒绝连接ciphers:${require('tls').DEFAULT_CIPHERS}@SECLEVEL=1``:在默认加密套件基础上降低安全级别,兼容目标服务器使用的旧版签名算法和证书配置
内容的提问来源于stack exchange,提问作者tsimon
相关产品推荐
相关产品推荐

