You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MQTTS客户端无法通过8883端口发布消息,证书验证异常

问题描述

我需要向一台全新的私有MQTT服务器(信息有限)发布数据,使用TLS协议(8883端口),遇到以下情况:

  • 关闭客户端证书验证(rejectUnauthorized: false)时,可正常发布和订阅消息;
  • 使用MQTTJS客户端并开启证书验证(rejectUnauthorized: true),配置如下:
async function testMqtt() {
  var options = {
    port: 8883,
    protocol: 'mqtts',
    username: 'username',
    password: 'password',
    rejectUnauthorized: true
  };
}

返回错误:

node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

Error: unable to verify the first certificate
    at TLSSocket.onConnectSecure (node:_tls_wrap:1674:34)
    at TLSSocket.emit (node:events:519:28)
    at TLSSocket._finishInit (node:_tls_wrap:1085:8)
    at ssl.onhandshakedone (node:_tls_wrap:871:12) {
  code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
}
  • 通过以下命令检查证书:
    • openssl s_client -connect server:443 | openssl.exe x509 > server443.cert 验证正常;
    • openssl s_client -connect server:8883 | openssl.exe x509 > server8883.cert 返回错误(verify error:num=20:unable to get local issuer certificate),但对比两个证书文件完全一致。

请问:

  1. 问题出在服务端还是客户端?
  2. 最佳解决方案是什么?
  3. 我可在客户端导入服务器证书,但服务器更新证书时客户端需同步更新;而浏览器用HTTPS时无需安装服务器证书,这是为什么?
问题分析与解答

1. 问题出在服务端

核心原因是MQTT服务端(8883端口)在TLS握手时未返回完整证书链,仅发送了服务器自身的叶子证书,未提供中间CA证书/根CA证书。

虽然443和8883端口使用的是同一个证书文件,但HTTPS服务端(443端口)正确配置了完整证书链,因此openssl验证正常;而MQTT服务端(8883端口)仅发送叶子证书,导致客户端无法完成证书信任链的验证,触发UNABLE_TO_VERIFY_LEAF_SIGNATURE错误。

2. 最佳解决方案

优先修复服务端配置:

  • 找到MQTT服务器的TLS配置项,将完整的证书链文件(包含叶子证书+中间CA证书,部分场景需补充根CA证书,顺序通常为叶子在前、根CA在后)配置到服务端,而非仅配置单独的服务器证书。
  • 确认证书链文件为PEM格式,多个证书直接拼接即可。

若暂时无法修改服务端,可采用客户端临时方案(不推荐长期使用,存在安全风险):

  • 在MQTTJS的options中添加ca字段,导入服务端的完整证书链(或根CA证书),示例:
const fs = require('fs');
async function testMqtt() {
  var options = {
    port: 8883,
    protocol: 'mqtts',
    username: 'username',
    password: 'password',
    rejectUnauthorized: true,
    ca: fs.readFileSync('./full-cert-chain.pem') // 导入完整证书链文件
  };
}

该方案存在证书更新后客户端需同步更新的问题,因此仍优先推荐修复服务端配置。

3. 浏览器HTTPS无需手动安装证书的原因

浏览器默认内置了主流根CA的证书列表。当HTTPS服务端返回完整证书链时,浏览器可通过内置根CA证书逐级验证叶子证书的有效性:

  1. 服务端返回叶子证书+中间CA证书;
  2. 浏览器用内置根CA证书验证中间CA证书的有效性;
  3. 再用验证通过的中间CA证书验证叶子证书,最终完成信任链建立。

而你的MQTT客户端(Node.js环境)默认信任根列表与浏览器不同,且MQTT服务端未返回完整证书链,导致客户端无法找到对应的信任根验证证书,因此需要手动导入证书或修复服务端的证书链配置。

内容的提问来源于stack exchange,提问作者timothé Faivre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 06:28:16