我试图从jira服务器下载一个文件使用URL,但我得到一个错误。 如何在代码中包含证书进行验证?

错误:

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);
      
    });
});

当前回答

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

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

其他回答

无法验证第一个证书

证书链不完整。

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

证书链

它很可能是这样的:

服务器证书——存储由中间体签署的证书。 中间证书——存储由根用户签名的证书。 根证书——存储自签名证书。

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

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

重现问题

使用浏览器访问https://incomplete-chain.badssl.com。

它没有显示任何错误(地址栏中的挂锁是绿色的)。 这是因为如果不是从服务器发送,浏览器倾向于完成链。

现在,使用Node连接到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扩展节点的内置证书存储,

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

1. 我如何获得中级证书?

使用openssl (Git 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

2 a。NODE_EXTRA_CA_CERTS

我使用cross-env在包中设置环境变量。json文件:

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

2 b。ca选项

该选项将覆盖Node的内置根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;

资源:

https://levelup.gitconnected.com/how-to-resolve-certificate-errors-in-nodejs-app-involving-ssl-calls-781ce48daded https://www.npmjs.com/package/ssl-root-cas https://github.com/nodejs/node/issues/16336 https://www.namecheap.com/support/knowledgebase/article.aspx/9605/69/how-to-check-ca-chain-installation https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file/ 如何将。crt转换为。pem

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

原因很简单-我不小心重新发送也“主机”头。 只是要确保你没有显式地发送“host”头。

您是否使用axios发送请求并得到此错误?

如果是这样,就把这看作是错误 无法验证第一个证书可能来自axios,与服务器无关。为了解决这个问题,您必须配置axios(或其他请求生成应用程序)以允许未经授权的请求。添加https。代理在请求的配置中设置rejectUnauthorized: false:

import axios from "axios"
import https from "https"

const getCities = async () => {
    try {
        const result = await axios.get("https://your-site/api/v1/get-cities", {
            httpsAgent: new https.Agent({
              rejectUnauthorized: false // set to false
            })
        })

        console.log(result.data)
    } catch(err) {
        console.log(err?.message||err)
    }
}

如果您正在使用自定义axios实例,则:

import axios from "axios"
import https from "https"

export const request = axios.create({
  baseURL: process.env.BASE_URL,
  headers: {
    Authorization: cookies.YOUR_ACCESS_TOKEN,
  },
  httpsAgent: new https.Agent({
    rejectUnauthorized: false //set to false
  })
})

我们已经提供了有效的根。pem和Intermediate。返回请求对象的agentOptions属性中的pem证书

ex:

   agentOptions: {
        ca: [
            fs.readFileSync("./ROOT.pem"),
            fs.readFileSync("./Intermediate.pem"),
        ],
    },

欲了解更多信息:https://stackoverflow.com/a/72582263/4652706

尝试添加适当的根证书

这总是比盲目接受未经授权的端点要安全得多,后者只能作为最后的手段。

这可以像添加一样简单

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

到你的应用程序。

SSL根ca npm包(这里使用的)对于这个问题是一个非常有用的包。