node.js 错误:无法验证 nodejs 中的第一个证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31673587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Error: unable to verify the first certificate in nodejs
提问by Labeo
I'm trying to download a file from jira server using an url but I'm getting an error. how to include certificate in the code to verify Error:
我正在尝试使用 url 从 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)
My Nodejs code:
我的 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);
});
});
采纳答案by Joshua
Try adding the appropriate root certificate
尝试添加适当的根证书
This is always going to be a much safer option than just blindly accepting unauthorised end points, which should in turn only be used as a last resort.
这总是比盲目接受未经授权的端点更安全的选择,而后者只能作为最后的手段。
This can be as simple as adding
这可以像添加一样简单
require('https').globalAgent.options.ca = require('ssl-root-cas/latest').create();
to your application.
到您的应用程序。
The SSL Root CAs npm package(as used here) is a very useful package regarding this problem.
该SSL根CA NPM包(这里使用的)是关于这个问题的一个非常有用的包。
回答by Satara
Another dirty hack, which will make all your requests insecure:
另一个肮脏的黑客,这将使您的所有请求不安全:
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
回答by Labeo
for unable to verify the first certificate in nodejs reject unauthorized is needed
由于无法验证 nodejs 中的第一个证书,因此需要拒绝未经授权
request({method: "GET",
"rejectUnauthorized": false,
"url": url,
"headers" : {"Content-Type": "application/json",
function(err,data,body) {
}).pipe(
fs.createWriteStream('file.html'));
回答by Flimm
The server you're trying to download from may be badly configured. Even if it works in your browser, it may not be including all the public certificates in the chain needed for a cache-empty client to verify.
您尝试从中下载的服务器可能配置不当。即使它在您的浏览器中工作,它也可能不包括缓存空客户端验证所需的链中的所有公共证书。
I recommend checking the site in SSLlabs tool: https://www.ssllabs.com/ssltest/
我建议在 SSLlabs 工具中检查站点:https://www.ssllabs.com/ssltest/
Look for this error:
查找此错误:
This server's certificate chain is incomplete.
此服务器的证书链不完整。
And this:
和这个:
Chain issues.........Incomplete
连锁问题.........不完整
回答by sch
unable to verify the first certificate
unable to verify the first certificate
The certificate chain is incomplete.
证书链不完整。
It means that the webserver you are connecting to is misconfigured and did not include the intermediate certificate in the certificate chain it sent to you.
这意味着您连接的网络服务器配置错误,并且在它发送给您的证书链中没有包含中间证书。
Certificate chain
证书链
It most likely looks as follows:
它很可能如下所示:
- Server certificate - stores a certificate signed by intermediate.
- Intermediate certificate - stores a certificate signed by root.
- Root certificate - stores a self-signed certificate.
- 服务器证书 - 存储由中间人签署的证书。
- 中间证书 - 存储由 root 签名的证书。
- 根证书 - 存储自签名证书。
Intermediate certificate should be installed on the server, along with the server certificate.
Root certificates are embedded into the software applications, browsers and operating systems.
中间证书应与服务器证书一起安装在服务器上。
根证书嵌入到软件应用程序、浏览器和操作系统中。
The application serving the certificate has to send the complete chain, this means the server certificate itself and all the intermediates. The root certificate is supposed to be known by the client.
服务证书的应用程序必须发送完整的链,这意味着服务器证书本身和所有中间件。客户端应该知道根证书。
Recreate the problem
重现问题
Go to https://incomplete-chain.badssl.comusing your browser.
使用浏览器访问https://incomplete-chain.badssl.com。
It doesn't show any error (padlock in the address bar is green).
It's because browsers tend to complete the chainif it's not sent from the server.
它没有显示任何错误(地址栏中的挂锁是绿色的)。
这是因为如果不是从服务器发送,浏览器往往会完成链。
Now, connect to https://incomplete-chain.badssl.comusing Node:
现在,使用 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);
});
Logs: "Error: unable to verify the first certificate".
日志:“错误:无法验证第一个证书”。
Solution
解决方案
You need to complete the certificate chain yourself.
您需要自己完成证书链。
To do that:
要做到这一点:
1:You need to get the missing intermediate certificate in .pemformat, then
1:需要获取.pem格式缺失的中间证书,然后
2a:extend Node's built-in certificate store using NODE_EXTRA_CA_CERTS,
2a:使用扩展节点的内置证书存储NODE_EXTRA_CA_CERTS,
2b:or pass your own certificate bundle (intermediates and root) using caoption.
2b:或使用ca选项传递您自己的证书包(中间和根)。
1. How do I get intermediate certificate?
1.如何获得中级证书?
Using openssl(comes with Git for Windows).
使用openssl(附带Git for Windows)。
Save the remote server's certificate details:
保存远程服务器的证书详细信息:
openssl s_client -connect incomplete-chain.badssl.com:443 -servername incomplete-chain.badssl.com | tee logcertfile
We're looking for the issuer (the intermediate certificate is the issuer / signer of the server certificate):
我们正在寻找颁发者(中间证书是服务器证书的颁发者/签署者):
openssl x509 -in logcertfile -noout -text | grep -i "issuer"
It should give you URI of the signing certificate. Download it:
它应该为您提供签名证书的 URI。下载它:
curl --output intermediate.crt http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
Finally, convert it to .pem:
最后,将其转换为.pem:
openssl x509 -inform DER -in intermediate.crt -out intermediate.pem -text
2a. NODE_EXTRA_CERTS
2a. NODE_EXTRA_CERTS
I'm using cross-envto set environment variables in package.jsonfile:
我正在使用cross-env在package.json文件中设置环境变量:
"start": "cross-env NODE_EXTRA_CA_CERTS=\"C:\Users\USERNAME\Desktop\ssl-connect\intermediate.pem\" node index.js"
2b. caoption
2b. ca选项
This option is going to overwrite the Node's built-in root CAs.
此选项将覆盖节点的内置根 CA。
That's why we need to create our own root CA. Use ssl-root-cas.
这就是为什么我们需要创建自己的根 CA。使用ssl-root-cas。
Then, create a custom httpsagent configured with our certificate bundle (root and intermediate). Pass this agent to axioswhen making request.
然后,创建一个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);
});
Instead of creating a custom httpsagent and passing it to axios, you can place the certifcates on the httpsglobal agent:
您可以将证书放在全局代理上,而不是创建自定义https代理并将其传递给:axioshttps
// Applies to ALL requests (whether using https directly or the request module)
https.globalAgent.options.ca = rootCas;
Resources:
资源:
- 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/
- How to convert .crt to .pem
- 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
回答by koolaang
This actually solved it for me, from https://www.npmjs.com/package/ssl-root-cas
这实际上为我解决了这个问题,来自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
});
回答by Sundar
You may be able to do this by modifying the request options as below. If you are using a self-signed certificate or a missing intermediary, setting strictSSL to false will not force request package to validate the certificate.
您可以通过如下修改请求选项来做到这一点。如果您使用的是自签名证书或缺少中介,则将 strictSSL 设置为 false 不会强制请求包验证证书。
var options = {
host: 'jira.example.com',
path: '/secure/attachment/206906/update.xlsx',
strictSSL: false
}
回答by Dean Christian Armada
GoDaddy SSL CCertificate
GoDaddy SSL 证书
I've experienced this while trying to connect to our backend API server with GoDaddy certificate and here is the code that I used to solve the problem.
我在尝试使用 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:
PS:
Use the bundled certificate and don't forget to install the library npm install ssl-root-cas
使用捆绑的证书,不要忘记安装库 npm install ssl-root-cas
回答by Vigneshwaran Ethirajan
This Worked For me => adding agent and 'rejectUnauthorized' set to false
这对我有用 => 添加代理并将“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;
});
};
回答by arva
Another approach to solve this is to use the following module.
解决此问题的另一种方法是使用以下模块。
node_extra_ca_certs_mozilla_bundle
node_extra_ca_certs_mozilla_bundle
This module can work without any code modification by generating a PEM file that includes all root and intermediate certificates trusted by Mozilla. You can use the following environment variable (Works with Nodejs v7.3+),
通过生成包含 Mozilla 信任的所有根证书和中间证书的 PEM 文件,该模块无需任何代码修改即可工作。您可以使用以下环境变量(适用于 Nodejs v7.3+),
To generate the PEM file to use with the above environment variable. You can install the module using:
生成与上述环境变量一起使用的 PEM 文件。您可以使用以下方法安装模块:
npm install --save node_extra_ca_certs_mozilla_bundle
and then launch your node script with an environment variable.
然后使用环境变量启动您的节点脚本。
NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js
Other ways to use the generated PEM file are available at:
其他使用生成的 PEM 文件的方法位于:
https://github.com/arvind-agarwal/node_extra_ca_certs_mozilla_bundle
https://github.com/arvind-agarwal/node_extra_ca_certs_mozilla_bundle
NOTE: I am the author of the above module.
注意:我是上述模块的作者。

