如何在Node.js中使用https.request忽略无效的自签名SSL证书?

422

我正在开发一个小应用程序,用于登录我的本地无线路由器(Linksys),但我遇到了路由器自签名SSL证书的问题。

我运行wget 192.168.1.1并得到以下结果:

ERROR: cannot verify 192.168.1.1's certificate, issued by `/C=US/ST=California/L=Irvine/O=Cisco-Linksys, LLC/OU=Division/CN=Linksys/emailAddress=support@linksys.com':
Self-signed certificate encountered.
ERROR: certificate common name `Linksys' doesn't match requested host name `192.168.1.1'.
To connect to 192.168.1.1 insecurely, use `--no-check-certificate'.

在Node中,被捕获的错误是:
{ [Error: socket hang up] code: 'ECONNRESET' }

我的当前示例代码如下:

我的当前示例代码如下:

var req = https.request({ 
    host: '192.168.1.1', 
    port: 443,
    path: '/',
    method: 'GET'

}, function(res){

    var body = [];
    res.on('data', function(data){
        body.push(data);
    });

    res.on('end', function(){
        console.log( body.join('') );
    });

});
req.end();

req.on('error', function(err){
    console.log(err);
});

我该如何让node.js实现等同于"--no-check-certificate"的功能?


1
对于在大流行的第四年来到这里的每个人,答案是:NODE_EXTRA_CA_CERTS。摇头,数百个糟糕的回复中唯一提到这个的只有2票。点赞此回答! - Ahmed Fasih
13个回答

805

便宜而不安全的答案:

添加

process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;

在调用 https.request() 前的代码中,

有一个更加安全的方式(上面的解决方案会使整个 Node 进程不安全),在这个问题中有答案。


2
对我来说非常好用!我将这段代码放在我的主应用程序js文件的最顶部,包含了所有内容后面。 - Xedecimal
51
不要在生产环境中使用此代码或"rejectUnauthorized",因为这会禁用所有安全检查。 - Jason Walton
4
我在使用Mocha运行自签名https节点服务器上的测试时遇到了问题,将此代码添加到任何describe块之前立即解决了我的问题。 - artis3n
5
这仅用于测试目的,不应在生产中使用。就像答案中所述,这并不是克服问题最安全的方式。 - Juanra
1
吹毛求疵:这应该是一个字符串'0'而不是数字0。环境变量始终为字符串,TypeScript也会相应地发出警告。 - jameshfisher
显示剩余6条评论

196

在您的请求选项中,尝试包括以下内容:

   var req = https.request({ 
      host: '192.168.1.1', 
      port: 443,
      path: '/',
      method: 'GET',
      rejectUnauthorized: false,
      requestCert: true,
      agent: false
    },

2
对我有用。我使用restler,我发现它默认没有转发选项,所以我不得不打补丁。 - Olivier Amblet
2
为了使此操作正常工作,您需要提供自定义代理的明确实例。创建选项对象并设置代理:'options.agent = new https.Agent(options);' 然后只需调用'https.request(options)'即可。 - Max
24
对我来说,仅使用 rejectUnauthorized 选项就足够了。没有其他的必要。 - mcont
1
@mcont 我确认只有 rejectUnauthorized 就足够了,其他的都是开箱即用的。我正在使用 VS Code 扩展程序。更好的做法是允许 PEM 配置,我下一步会这样做... - escape-llc
requestCert 是用于服务器的。 - Ali

82

添加以下环境变量:

NODE_TLS_REJECT_UNAUTHORIZED=0

例如,使用export命令:

export NODE_TLS_REJECT_UNAUTHORIZED=0

(感谢Juanra的大力协助)


当我尝试运行 webdriver-manager update 时,这对我起作用了。 - Ashley
5
在Windows中设置NODE_TLS_REJECT_UNAUTHORIZED=0。 - Felipe SS
1
这是我的开发环境的一个很好的解决方案。 - David
挽救了我的夜晚。 - msonowal

81

不要相信那些试图误导你的人。

在您的请求中,只需添加:

ca: [fs.readFileSync([certificate path], {encoding: 'utf-8'})]

如果您启用未经授权的证书,您将完全没有保护(暴露于MITM攻击中,因为未验证身份),而且没有SSL的工作也不会有很大的区别。解决方案是指定您期望的CA证书,如下代码片段所示。请确保证书的公共名称与请求中调用的地址(如主机中指定的)相同:

那么您将获得以下内容:

var req = https.request({ 
      host: '192.168.1.1', 
      port: 443,
      path: '/',
      ca: [fs.readFileSync([certificate path], {encoding: 'utf-8'})],
      method: 'GET',
      rejectUnauthorized: true,
      requestCert: true,
      agent: false
    },

请阅读此文章(注意:此答案作者撰写的博客文章),以了解以下内容:

  • CA证书的工作原理
  • 如何轻松生成用于测试的CA证书,以模拟生产环境

9
这个方法可行且是修复“错误:证书链中的自签名证书”的正确方式。 - RohanRasane
1
为什么你把fs.readFileSync放在括号里,而不是将其存储为字符串? - Lelo
Lelo:括号将其转换为数组。ca:期望证书数组。该文件应该是证书的逗号分隔列表,通常人们使用内部函数将PEM文件转换为数组。对于自签名证书,单个证书“应该”可以工作。 - JohnDavid
这段代码仍然有 "rejectUnauthorized: true"。这与其他禁用证书授权的答案有何不同? - spryce
@spryce rejectUnauthorized: true 启用 SSL 验证。 - Gershom Maes
这似乎是在一个空间中的“正确”方法,但它对OP没有帮助 - 证书中的CN(“linksys”)不会被识别为192.168.1.1(除非自定义DNS配置在OP网络中执行)。自签名证书用于为具有动态IP的测试系统进行配置,或为将在没有事先了解用于访问它们的CN的情况下部署的设备提供TLS支持。在这种情况下,使用选项rejectUnauthorized:false是正确的方法,前提是开发人员将其限制为那些“动态”资源并接受随之而来的风险... - Francois Connetable

25

补充@Armand的答案:

添加以下环境变量:

NODE_TLS_REJECT_UNAUTHORIZED=0 例如使用export:

export NODE_TLS_REJECT_UNAUTHORIZED=0 (非常感谢Juanra)

如果你在Windows上使用:

set NODE_TLS_REJECT_UNAUTHORIZED=0

感谢:@weagle08


17

您还可以使用默认选项创建请求实例:

require('request').defaults({ rejectUnauthorized: false })

谢谢,这对解决登录 Surge 时出现的“Error: unable to get local issuer certificate”问题也有很大帮助。 - Tobi

7
所以,我的公司刚刚转换到Node.js v12.x。我曾经使用过NODE_TLS_REJECT_UNAUTHORIZED,但它停止工作了。经过一些挖掘,我开始使用NODE_EXTRA_CA_CERTS=A_FILE_IN_OUR_PROJECT,它具有我们自签名证书的PEM格式,现在我的所有脚本都能正常工作了。
因此,如果您的项目有自签名证书,也许这个环境变量可以帮助您。
参考:https://nodejs.org/api/cli.html#cli_node_extra_ca_certs_file

1
如果您能提供根CA,那么此答案效果最佳,比完全禁用证书检查要好得多。 - datu-puti

4

try export NODE_TLS_REJECT_UNAUTHORIZED=0


3
对于meteorJS,您可以使用npmRequestOptions进行设置。
HTTP.post(url, {
    npmRequestOptions: {
        rejectUnauthorized: false // TODO remove when deploy
    },
    timeout: 30000, // 30s
    data: xml
}, function(error, result) {
    console.log('error: ' + error);
    console.log('resultXml: ' + result);
});

1

当你无法控制请求创建时

在使用包时,有时您无法在request调用上设置正确的设置,也没有包提供一种注入request的方法。

但是,您可能仍希望避免不安全的NODE_TLS_REJECT_UNAUTHORIZED=0,并选择仅与指定目标建立不安全的连接。

这是我解决问题的方法:

// check if host and port fit your application
function isSelf(host, port) {
  return host === myHost && port === myPort;
}

// get the built in tls module and overwrite the default connect behavior 
const tls = require("tls");
const _connect = tls.connect;
function wrappedConnect(options, secureConnectListener) {
  if (isSelf(options.host, options.port)) {
    options.rejectUnauthorized = false;
  }
  return _connect(options, secureConnectListener);
}
tls.connect = wrappedConnect;

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