无法验证叶签名

Posted

技术标签:

【中文标题】无法验证叶签名【英文标题】:Unable to verify leaf signature 【发布时间】:2013-12-03 16:12:42 【问题描述】:

我正在使用 node.js request.js 来访问 api。我收到此错误

[错误:UNABLE_TO_VERIFY_LEAF_SIGNATURE]

我所有的凭据都是准确有效的,服务器也很好。我向邮递员提出了同样的要求。

request(
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":
        "X-API-VERSION": 1,
        "X-API-KEY": key
    ,
, function(err, response, body)
    console.log(err);
    console.log(response);
    console.log(body);
);

此代码只是在可执行脚本 ex 中运行。 node ./run_file.js,这是为什么呢?它需要在服务器上运行吗?

【问题讨论】:

这是一个长镜头,但可能是 API 无法识别您的节点程序正在传递的用户代理吗? 哼...另见:blog.gaeremynck.com/fixing-unable_to_verify_leaf_signature @HectorCorrea 我能够完美地阅读邮递员中的 api。为什么节点不能这样做?我尝试更改用户代理,但没有成功。 【参考方案1】:

你好只是这个主题的一个小补充,因为在我的例子中

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

对我来说没用,它一直返回无法下载文件的错误,当我遇到此响应 https://***.com/a/65442604

由于在我的应用程序中,我们确实有一个代理来代理我们的一些请求,作为我们一些用户的安全要求,我发现如果您正在咨询有此问题的 API,并且您是否可以访问 API url通过您的浏览器,您可以代理您的请求,它可能会解决 [错误:UNABLE_TO_VERIFY_LEAF_SIGNATURE] 问题。

我如何使用代理的示例

await axios.get(url, 
  timeout: TIME_OUT,
  headers: 
    'User-Agent': 'My app'
  ,
  params: params,
  proxy: 
    protocol: _proxy.protocol,
    host: _proxy.hostname,
    port: _proxy.port,
    auth: 
      username: _proxy_username,
      password: _proxy_password
    
  
);

【讨论】:

【参考方案2】:

安全解决方案

您可以将必要的证书添加到链中,而不是关闭安全性。首先从 npm 安装 ssl-root-cas 包:

npm install ssl-root-cas

此包包含许多浏览器信任但节点不信任的中间证书。

var sslRootCAs = require('ssl-root-cas/latest')
sslRootCAs.inject()

将添加缺少的证书。请参阅此处了解更多信息:

https://git.coolaj86.com/coolaj86/ssl-root-cas.js

【讨论】:

Http 客户端是否不使用 Windows 受信任的根证书颁发机构证书存储区? node 使用捆绑在二进制文件中的 mozilla 证书,只要您提供自己的 ca 数组,它就会覆盖它们。我不知道它的 http 模块是否也会查看 OS 链。但是,OS X 上的 curl 似乎只使用 OS 链,不允许手动指定证书。 这是否必须为每个进程运行,还是我可以运行一次并在全球范围内更新我的证书? @Sunkas 这正是错误消息所说的。我不知道如何更简单地解释它。这是一个只读文件,不能编辑。 我赞成的不是答案本身,而是作者提供的链接后面带有“首先尝试”解释的文章。干得好@coolaj86!实际上有帮助【参考方案3】:

以下命令对我有用:

> npm config set strict-ssl false
> npm cache clean --force

问题是您试图从带有错误或不受信任的 SSL[安全套接字层] 证书的存储库安装模块。清理缓存后,此问题将得到解决。您可能需要稍后将其设置为 true。

【讨论】:

【参考方案4】:

如果你是因为使用节点 postgres / pg 模块而来到这个帖子,有比设置NODE_TLS_REJECT_UNAUTHORIZEDrejectUnauthorized 更好的解决方案,这会导致不安全的连接。

相反,配置“ssl”选项以匹配tls.connect的参数:


  ca: fs.readFileSync('/path/to/server-ca.pem').toString(),
  cert: fs.readFileSync('/path/to/client-cert.pem').toString(),
  key: fs.readFileSync('/path/to/client-key.pem').toString(),
  servername: 'my-server-name' // e.g. my-project-id/my-sql-instance-id for Google SQL

我编写了一个模块来帮助从环境变量(如PGSSLROOTCERTPGSSLCERTPGSSLKEY)解析这些选项:

https://github.com/programmarchy/pg-ssl

【讨论】:

【参考方案5】:

您也可以尝试将 strictSSL 设置为 false,如下所示:

  
   url: "https://...",
   method: "POST",
   headers: 
        "Content-Type": "application/json",
   strictSSL: false

【讨论】:

如果您从 Node JS 应用程序发送,这可以工作,太棒了!! 谢谢!!!它对我有用,哇,花了这么多时间......【参考方案6】:

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

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

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

【讨论】:

【参考方案7】:

rejectUnauthorized: falseprocess.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; 可能非常诱人,但不要这样做!它会让你暴露在中间人的攻击之下。

其他答案是正确的,因为问题在于您的证书是“由中间 CA 签名的”。有一个简单的解决方案,它不需要像 ssl-root-cas 这样的第三方库或将任何额外的 CA 注入节点。

节点中的大多数 https 客户端都支持允许您为每个请求指定 CA 的选项,这将解析 UNABLE_TO_VERIFY_LEAF_SIGNATURE。这是一个使用 node 内置的 https 模块的简单示例。

import https from 'https';

const options = 
  host: '<your host>',
  defaultPort: 443,
  path: '<your path>',
  // assuming the bundle file is co-located with this file
  ca: readFileSync(__dirname + '/<your bundle file>.ca-bundle'),
  headers: 
    'content-type': 'application/json',
  
;
https.get(options, res => 
  // do whatever you need to do
)

但是,如果您可以在托管服务器中配置 ssl 设置,最好的解决方案是将中间证书添加到您的托管服务提供商。这样,客户端请求者不需要指定 CA,因为它包含在服务器本身中。我个人使用 namecheap + heroku。对我来说,诀窍是用cat yourcertificate.crt bundle.ca-bundle &gt; server.crt 创建一个.crt 文件。然后我打开了这个文件并在第一个证书之后添加了一个换行符。您可以阅读更多内容

https://www.namecheap.com/support/knowledgebase/article.aspx/10050/33/installing-an-ssl-certificate-on-heroku-ssl

【讨论】:

这个 bug 主要出现在本地环境中,而不是生产环境中,所以如果你在本地环境中可以这样做:process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; @Vivex - 如果整个目的是测试您的 SSL 证书如何工作以及它们是如何传递的,那么在本地环境中这样做是不行的......【参考方案8】:

您必须在服务器中包含中间证书。这解决了[错误:UNABLE_TO_VERIFY_LEAF_SIGNATURE]

【讨论】:

【参考方案9】:

我也有同样的问题。我遵循了@ThomasReggi 和@CoolAJ86 解决方案,效果很好,但我对解决方案不满意。

因为认证配置级别出现“UNABLE_TO_VERIFY_LEAF_SIGNATURE”问题。

我接受@thirdender 解决方案,但它的部分解决方案。根据nginx 官方网站,他们明确提到证书应该是服务器证书和链式证书的组合。

【讨论】:

【参考方案10】:

对于 Create React App(也会出现此错误,并且此问题是 Google 排名第一的结果),您可能正在使用 HTTPS=true npm startproxy(在 package.json 中)在开发时转到一些本身是自签名的 HTTPS API。

如果是这种情况,请考虑像这样更改proxy

"proxy": 
  "/api": 
    "target": "https://localhost:5001",
    "secure": false
  

secure 决定 WebPack 代理是否检查证书链并禁用以确保 API 自签名证书未经过验证,以便您获取数据。

【讨论】:

【参考方案11】:

注意:以下是危险的,将允许在客户端和服务器之间截取和修改 API 内容。

这也有效

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

【讨论】:

我更新了这个,感谢您的回答,但它对您的安全有害。您应该按照下面@CoolAJ86 的回答添加缺少的 CA。 我正在使用名为 nodemailernodemailer-smtp-transport 的 NodeJS 插件,并且使用相同的通用命令。您需要将此添加到您的 createTransport 对象中:tls:rejectUnauthorized: false @LukeP 我猜 nodemailer 同样不安全。名称中有一个线索:如果某件事是授权的,根据定义,您通常想要拒绝它。您需要找到一种正确授权的方法(通过正确设置 CA 证书,正如其他答案已经说过的那样)。 @Bruno 我同意,您应该使用证书以正确的方式设置它。我只是想为演示设置一个快速测试,所以我发布的代码是一个快速修复。我应该在我的评论中以此作为开头。 @mikemaccana 如果请求在同一台服务器上并且您是唯一的所有者,则没有安全问题。【参考方案12】:

在子域上安装 GoDaddy 证书后,我的 Apache 配置出现问题。我最初认为这可能是 Node 未发送服务器名称指示符 (SNI) 的问题,但事实并非如此。使用 https://www.ssllabs.com/ssltest/ 分析子域的 SSL 证书返回错误 Chain issues: Incomplete

在通过 SSLCertificateChainFile Apache 指令添加 GoDaddy 提供的 gd_bundle-g2-g1.crt 文件后,Node 能够通过 HTTPS 连接并且错误消失了。

【讨论】:

【参考方案13】:

只是把它放在这里以防它对某人有帮助,我的情况不同,而且有点奇怪。我是在通过superagent 访问的请求中得到这个的——这个问题与证书(设置正确)无关,而与我随后通过async 模块传递超级代理结果的事实有关瀑布回调。解决方法:不要传递整个结果,只需通过瀑布的回调传递 result.body

【讨论】:

【参考方案14】:

CoolAJ86 的解决方案是正确的,它不会损害您的安全性,例如使用rejectUnauthorizedNODE_TLS_REJECT_UNAUTHORIZED 禁用所有检查。不过,您可能需要显式注入额外的 CA 证书。

我首先尝试了 ssl-root-cas 模块中包含的根 CA:

require('ssl-root-cas/latest')
  .inject();

我仍然遇到UNABLE_TO_VERIFY_LEAF_SIGNATURE 错误。然后我通过COMODO SSL Analyzer找到了谁为我正在连接的网站颁发了证书,下载了该机构的证书并尝试只添加那个:

require('ssl-root-cas/latest')
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

我遇到了另一个错误:CERT_UNTRUSTED。最后,我注入了额外的根 CA,并包含了“我的”(显然是中间的)CA,它起作用了:

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

【讨论】:

我使用 COMODO High-Assurance Secure Server CA 颁发的证书连接到一个网站。我从他们的downloads page 下载了证书。 谢谢!对于我的问题,我需要添加整个证书链来克服这个错误。供其他人参考,这篇文章向我展示了如何通过 Firefox 轻松导出所需的 pem 文件:superuser.com/a/97203 感谢您的帮助。就我而言,最终这是 SSL 服务器的错误配置,而不是节点。并非所有中间证书都安装在服务器上。 如果您以.cer 的形式获得证书,请运行此openssl x509 -inform DER -in YOUR_CERTIFICATE.cer -out YOUR_CERTIFICATE.crt 以预先将其转换为.crt【参考方案15】:

这不是应用程序的问题,而是由中间 CA 签署的证书的问题。 如果您接受这一事实并仍想继续,请在请求选项中添加以下内容:

rejectUnauthorized: false

完整请求:

request(
    "rejectUnauthorized": false,
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":
        "X-API-VERSION": 1,
        "X-API-KEY": key
    ,
, function(err, response, body)
    console.log(err);
    console.log(response);
    console.log(body);
);

【讨论】:

我现在在工作中遇到了这个问题。我提交了一张 IT 票,告诉他们 SSL 可能配置错误——他们告诉我我疯了。我可以提供更多信息来解决此问题吗? 这实际上是不正确的:正如 CoolAJ86 和 hectorcorrea 所提到的,证书是有效的,但它是由中间 CA 签名的。

以上是关于无法验证叶签名的主要内容,如果未能解决你的问题,请参考以下文章

无法验证签名 (cmssigneddata) bouncycastle

接收方无法验证签名的 XML 消息

UseJwtBearerAuthentication 失败并显示 IDX10504:无法验证签名,令牌没有签名

由于没有公钥,无法验证下列签名

由于没有公钥,无法验证下列签名

Spring Security SAML - 无法验证签名