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

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

错误:

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

});
});
562640 次浏览

对于无法验证nodejs中的第一个证书,需要拒绝未经授权的证书

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

尝试添加适当的根证书

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

这可以像添加一样简单

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

到你的应用程序。

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

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

我建议在SSLlabs工具中检查该站点:https://www.ssllabs.com/ssltest/

查找以下错误:

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

这:

链问题……不完整

您可以通过如下所示修改请求选项来做到这一点。如果使用自签名证书或缺少中介,将strictSSL设置为false将不会强制请求包验证证书。

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

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

另一个肮脏的黑客,这将使你所有的请求不安全:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

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

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

这实际上为我解决了它,从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
});

这为我工作=>添加代理和'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;
});
};

unable to verify the first certificate

证书链不完整。

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

证书链

它很可能是这样的:

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

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

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

重现问题

使用浏览器访问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);
});

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

解决方案

您需要自己完成证书链。

做那件事:

那么,你需要以.pem格式获取缺少的中间证书

使用NODE_EXTRA_CA_CERTS扩展节点的内置证书存储,

2 b:或使用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_CERTS

我使用cross-envpackage.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全局代理上,而不是创建自定义的https代理并将其传递给axios:

// 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/ < a href = " https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file/ " > < / >
  6. 如何将.crt转换为.pem .pem

您可以全局禁用证书检查-无论您使用哪个包来发出请求-就像这样:

// 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

当然,您不应该这样做——但这对于调试和/或非常基本的脚本编写非常方便,您完全不需要关心证书是否正确验证。

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

对我来说,当我试图使用axios获取数据或获取库时,就发生了这种情况,因为我在公司防火墙下,所以我们有某些特定的证书,node js证书存储无法指向。

所以对于我的localhost,我遵循了这种方法。 我在我的项目中创建了一个文件夹,并在文件夹中保存了整个证书链,在我的脚本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

在我的例子中,我没有生成任何证书,因为整个证书链对我来说已经可用了。

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

原因很简单-我不小心重新发送了"host"头。 只要确保你没有发送“;host"标题明确。< / p >

我可以通过mozilla或chrome等浏览器获得证书链。

  1. 打开网站,进入网页的证书设置,下载证书链作为文件名(first-chain. txt)。Pem, second-chain.pem),应该是Pem格式
----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
......
-----END CERTIFICATE-----
----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
......
-----END CERTIFICATE-----
  1. 然后在你的nodejs代码中,我在typescript上做了,我添加了2个cas,因为我有2个webserver请求
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添加定义文件,以便typescript不会报错

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

在dev env中设置:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

或者,首先设置环境变量

export NODE_TLS_REJECT_UNAUTHORIZED=0

然后启动应用程序:

node index.js

不适用于促销服务。

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

如果是,考虑这个错误 unable to verify the first certificate可以来自axios,与服务器无关。为了解决这个问题,你必须配置axios(或其他请求制作应用程序)来允许未经授权的请求。在请求的配置中添加https.Agent来设置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
})
})

这对我很有效

做下面的事情

如果你没有这些包httpsaxios

你可以通过 NPM install——save axios https

import axios from 'axios';
import https from 'https';
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
})


axios.defaults.httpsAgent = httpsAgent

这样做你就会得到你的回应。

我们已经在请求对象的agentOptions属性中提供了有效的Root.pem and Intermediate.pem证书

例:

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

有关更多信息:https://stackoverflow.com/a/72582263/4652706