错误:无法验证nodejs中的第一个证书

时间:2015-07-28 10:23:07

标签: node.js ssl-certificate jira

我尝试使用网址从jira服务器下载文件,但我收到了错误消息。 如何在代码中包含证书以进行验证 的错误:

Error: unable to verify the first certificate in nodejs

at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:929:36)

  at TLSSocket.emit (events.js:104:17)

at TLSSocket._finishInit (_tls_wrap.js:460:8)

我的Nodejs代码:

var https = require("https");
var fs = require('fs');
var options = {
    host: 'jira.example.com',
    path: '/secure/attachment/206906/update.xlsx'
};

https.get(options, function (http_res) {

    var data = "";


    http_res.on("data", function (chunk) {

        data += chunk;
    });


    http_res.on("end", function () {

        var file = fs.createWriteStream("file.xlsx");
        data.pipe(file);

    });
});

16 个答案:

答案 0 :(得分:80)

尝试添加适当的根证书

除了盲目接受未经授权的终点之外,这总是比一个更安全的选择,而这应该只是作为最后的手段使用。

这可以像添加

一样简单
require('https').globalAgent.options.ca = require('ssl-root-cas/latest').create();

到你的申请。

SSL Root CAs npm package(这里使用的)是关于这个问题的一个非常有用的包。

答案 1 :(得分:54)

unable to verify the first certificate

证书链不完整。

这意味着您要连接的Web服务器配置错误,并且在发送给您的证书链中未包含中间证书。

证书链

最有可能如下所示:

  1. 服务器证书-存储由中间人签名的证书。
  2. 中间证书-存储由root签名的证书。
  3. 根证书-存储自签名证书。

中间证书应与服务器证书一起安装在服务器上。
根证书已嵌入到软件应用程序,浏览器和操作系统中。

提供证书的应用程序必须发送完整的链,这意味着服务器证书本身以及所有中间产品。客户端应该知道根证书。

重新创建问题

使用浏览器转到https://incomplete-chain.badssl.com

它没有显示任何错误(地址栏中的挂锁为绿色)。
这是因为浏览器往往不是从服务器发送来的,便会完成该链

现在,使用节点连接到https://incomplete-chain.badssl.com

// index.js
const axios = require('axios');

axios.get('https://incomplete-chain.badssl.com')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

日志:“ 错误:无法验证第一个证书”。

解决方案

您需要自己完成证书链。

要这样做:

1::您需要以.pem格式获取丢失的中间证书,然后

2a:使用NODE_EXTRA_CA_CERTS

扩展Node的内置证书存储

2b:或使用ca选项传递您自己的证书捆绑包(中间件和根)。

1。如何获得中间证书?

使用opensslGit for Windows附带)。

保存远程服务器的证书详细信息:

openssl s_client -connect incomplete-chain.badssl.com:443 -servername incomplete-chain.badssl.com | tee logcertfile

我们正在寻找颁发者(中间证书是服务器证书的颁发者/签名者):

openssl x509 -in logcertfile -noout -text | grep -i "issuer"

它应该给您签名证书的URI。下载:

curl --output intermediate.crt http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt

最后,将其转换为.pem

openssl x509 -inform DER -in intermediate.crt -out intermediate.pem -text

2a。 NODE_EXTRA_CERTS

我正在使用cross-envpackage.json文件中设置环境变量:

"start": "cross-env NODE_EXTRA_CA_CERTS=\"C:\\Users\\USERNAME\\Desktop\\ssl-connect\\intermediate.pem\" node index.js"

2b。 ca选项

此选项将覆盖节点的内置根CA。

这就是为什么我们需要创建自己的根CA。使用ssl-root-cas

然后,创建一个自定义https代理,该代理配置了我们的证书捆绑包(根证书和中间证书)。提出请求时,将此代理传递给axios

// index.js
const axios = require('axios');
const path = require('path');
const https = require('https');
const rootCas = require('ssl-root-cas').create();

rootCas.addFile(path.resolve(__dirname, 'intermediate.pem'));
const httpsAgent = new https.Agent({ca: rootCas});

axios.get('https://incomplete-chain.badssl.com', { httpsAgent })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

您可以将证书放在https全局代理上,而不用创建自定义的axios代理并将其传递给https

// Applies to ALL requests (whether using https directly or the request module)
https.globalAgent.options.ca = rootCas;

资源:

  1. https://levelup.gitconnected.com/how-to-resolve-certificate-errors-in-nodejs-app-involving-ssl-calls-781ce48daded
  2. https://www.npmjs.com/package/ssl-root-cas
  3. https://github.com/nodejs/node/issues/16336
  4. https://www.namecheap.com/support/knowledgebase/article.aspx/9605/69/how-to-check-ca-chain-installation
  5. https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file/
  6. How to convert .crt to .pem

答案 2 :(得分:32)

无法验证nodejs中的第一个证书是否需要未经授权

 request({method: "GET", 
        "rejectUnauthorized": false, 
        "url": url,
        "headers" : {"Content-Type": "application/json",
        function(err,data,body) {
    }).pipe(
       fs.createWriteStream('file.html'));

答案 3 :(得分:25)

另一个肮脏的黑客攻击,会使你的所有请求都不安全:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

答案 4 :(得分:18)

您尝试下载的服务器配置可能不正确。即使它在您的浏览器中有效,它也可能不包括缓存空客户端验证所需的链中的所有公共证书。

我建议您使用SSLlabs工具检查网站:https://www.ssllabs.com/ssltest/

查找此错误:

  

此服务器的证书链不完整。

而且:

  

连锁问题.........不完整

答案 5 :(得分:5)

您可以通过修改请求选项来执行此操作,如下所示。如果您使用自签名证书或缺少中间人,则将strictSSL设置为false将不会强制请求包验证证书。

var options = {
   host: 'jira.example.com',
   path: '/secure/attachment/206906/update.xlsx',
   strictSSL: false
}

答案 6 :(得分:1)

GoDaddy SSL CCertificate

我尝试使用GoDaddy证书连接到我们的后端API服务器时遇到过这种情况,这是我用来解决问题的代码。

var rootCas = require('ssl-root-cas/latest').create();

rootCas
  .addFile(path.join(__dirname, '../config/ssl/gd_bundle-g2-g1.crt'))
  ;

// will work with all https requests will all libraries (i.e. request.js)
require('https').globalAgent.options.ca = rootCas;

<强> PS:

使用捆绑的证书,不要忘记安装库npm install ssl-root-cas

答案 7 :(得分:1)

这实际上为我解决了问题,https://www.npmjs.com/package/ssl-root-cas

// INCORRECT (but might still work)
var server https.createServer({
  key: fs.readFileSync('privkey.pem', 'ascii')
, cert: fs.readFileSync('cert.pem', 'ascii')   // a PEM containing ONLY the SERVER certificate
});

// CORRECT (should always work)
var server https.createServer({
  key: fs.readFileSync('privkey.pem', 'ascii')
, cert: fs.readFileSync('fullchain.pem', 'ascii') // a PEM containing the SERVER and ALL INTERMEDIATES
});

答案 8 :(得分:1)

您可以全局禁用证书检查-不管您使用哪个软件包进行请求-

// Disable certificate errors globally
// (ES6 imports (eg typescript))
//
import * as https from 'https'
https.globalAgent.options.rejectUnauthorized = false

// Disable certificate errors globally
// (vanilla nodejs)
//
require('https').globalAgent.options.rejectUnauthorized = false

当然您不应该这样做-但对于调试和/或非常基本的脚本而言,它绝对方便,因为您绝对不关心证书是否正确验证。

答案 9 :(得分:0)

我正在使用nodemailer npm模块。下面的代码解决了这个问题

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }

答案 10 :(得分:0)

  

这对我有用=>添加代理并将'rejectUnauthorized'设置为false

const https = require('https'); //Add This
const bindingGridData = async () => {
  const url = `your URL-Here`;
  const request = new Request(url, {
    method: 'GET',
    headers: new Headers({
      Authorization: `Your Token If Any`,
      'Content-Type': 'application/json',
    }),
    //Add The Below
    agent: new https.Agent({
      rejectUnauthorized: false,
    }),
  });
  return await fetch(request)
    .then((response: any) => {
      return response.json();
    })
    .then((response: any) => {
      console.log('response is', response);
      return response;
    })
    .catch((err: any) => {
      console.log('This is Error', err);
      return;
    });
};

答案 11 :(得分:0)

解决此问题的另一种方法是使用以下模块。

node_extra_ca_certs_mozilla_bundle

该模块可以通过生成包含Mozilla信任的所有根证书和中间证书的PEM文件而无需进行任何代码修改即可工作。您可以使用以下环境变量(适用于Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

生成与以上环境变量一起使用的PEM文件。您可以使用以下命令安装模块:

npm install --save node_extra_ca_certs_mozilla_bundle

,然后使用环境变量启动节点脚本。

NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js

使用其他方法来生成生成的PEM文件:

https://github.com/arvind-agarwal/node_extra_ca_certs_mozilla_bundle

注意:我是上述模块的作者。

答案 12 :(得分:0)

几天前我遇到了这个问题,这是我遵循的方法,并且对我有效。

对我来说,这是在我尝试使用axios或在公司防火墙下获取库时发生的,所以我们有某些特定的证书,node js证书存储无法指向。

因此,对于我的loclahost,我采用了这种方法。 我在项目中创建了一个文件夹,并将整个证书链保留在该文件夹中以及我的dev-server( package.json )脚本中,并与服务器脚本一起添加,以便节点js可以引用路径。

"dev-server":set NODE_EXTRA_CA_CERTS=certificates/certs-bundle.crt

对于我的服务器(不同的环境),我如下创建了一个新的环境变量,并添加了它。我使用的是Openshift,但我想这个概念对于其他服务器也将相同。

"name":NODE_EXTRA_CA_CERTS
"value":certificates/certs-bundle.crt

由于我已经可以使用整个证书链,因此我没有生成任何证书。

答案 13 :(得分:0)

我遇到了非常罕见的情况,但希望它可以对某人有所帮助:制作了一个代理服务,将请求代理到另一个服务。即使我添加了所有预期的证书,每个请求的错误都是“无法验证第一个证书”。

原因很简单 - 我不小心重新发送了“主机”标头。 只要确保您没有明确发送“主机”标头即可。

答案 14 :(得分:0)

我能够通过 mozilla 或 chrome 等浏览器获取证书链。

  1. 打开网站,进入网页的证书设置,下载证书链作为文件名(first-chain.pem, second-chain.pem),应该是pem格式的
<块引用>
----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
......
-----END CERTIFICATE-----
----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
......
-----END CERTIFICATE-----
  1. 然后在您的 nodejs 代码中,我是在打字稿上完成的,我添加了 2 个 cas,因为我有 2 个网络服务器请求
<块引用>
import https from 'https'
import cas from 'ssl-root-cas'

......

<块引用>
 interface CaList extends Buffer {
  addFile(file: string): Buffer[]
 }
 const caList = cas.create() as CaList
 caList.addFile(process.env.PROJECT_PATH + 'certs/first-chain.pem')
 caList.addFile(process.env.PROJECT_PATH + 'certs/second-chain.pem')

然后当我需要建立 websocket wss 连接时,我将带有新 cas 列表的代理添加到请求中

<块引用>
this.client.connect(KtUrl, undefined, undefined, undefined, {
    agent: new https.Agent({
      ca: caList
    })
})

还必须为 ssl-root-cas 文件名添加定义文件 ssl-root-cas.d.ts 以便打字稿不会抱怨

<块引用>
declare module 'ssl-root-cas' {
  function create(): string | Buffer | (string | Buffer)[] | undefined
}

答案 15 :(得分:0)

在开发环境中设置: process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';