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),但对比两个证书文件完全一致。
请问:
- 问题出在服务端还是客户端?
- 最佳解决方案是什么?
- 我可在客户端导入服务器证书,但服务器更新证书时客户端需同步更新;而浏览器用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证书逐级验证叶子证书的有效性:
- 服务端返回叶子证书+中间CA证书;
- 浏览器用内置根CA证书验证中间CA证书的有效性;
- 再用验证通过的中间CA证书验证叶子证书,最终完成信任链建立。
而你的MQTT客户端(Node.js环境)默认信任根列表与浏览器不同,且MQTT服务端未返回完整证书链,导致客户端无法找到对应的信任根验证证书,因此需要手动导入证书或修复服务端的证书链配置。
内容的提问来源于stack exchange,提问作者timothé Faivre
相关产品推荐
相关产品推荐

