Mosquitto 1.3.2 安全修复解读:认证插件错误处理、桥接 TLS 校验与 ACL 加固实践

发布时间:2026/9/23 15:01:39
Mosquitto 1.3.2 安全修复解读:认证插件错误处理、桥接 TLS 校验与 ACL 加固实践 后端消息队列消息路由【免费下载链接】mosquittoEclipse Mosquitto - An open source MQTT broker项目地址https://gitcode.com/gh_mirrors/mos/mosquitto点击查看免费下载本文以 Eclipse Mosquitto 1.3.2 官方发布说明www/posts/2014/07/version-1-3-2-released.md为主线系统剖析该安全与缺陷修复版本涉及的认证插件漏洞成因、Broker 侧 ACL/桥接行为变更、客户端库修复及构建改进并结合当前仓库源码给出可验证的实现依据与升级建议。读完本文你将理解MOSQ_ERR_UNKNOWN被误判为认证成功的根因与正确处置方式掌握模式 ACL、$开头主题订阅、TLS 桥接证书校验等关键配置的注意点并能为使用认证插件的生产环境制定安全的升级与排查方案。一、版本定位为什么 1.3.2 是一次必须升级的发布Mosquitto 1.3.2 于 2014 年 7 月 13 日发布见 ChangeLog.txt 中1.3.2 - 20140713条目官方定性为security and bugfix release安全与缺陷修复版本。它不是新功能版本其价值集中在修复一个可导致未授权客户端访问 Broker的认证插件漏洞bug #1340782修复多个可能导致崩溃、订阅丢失、消息错乱的 Broker 缺陷修复客户端库在线程接口、主题匹配、CMake 构建 SRV 支持方面的三个问题改进安装阶段的交叉编译便利性。对使用第三方认证插件的用户官方明确提示 This is an important update这是一次重要更新必须尽快升级。二、安全修复认证插件返回应用错误时禁止放行客户端2.1 漏洞现象与危害发布说明指出当 mosquitto 使用插件做认证时如果插件在一次认证检查中返回MOSQ_ERR_UNKNOWN例如后端数据库暂不可用时旧版本 mosquitto 会错误地将该返回值当作认证成功处理。其后果是未授权客户端可能接入正在运行的 mosquitto broker并访问其本无权访问的信息。这是一个典型的失败-开放fail-open安全缺陷底层认证依赖数据库、LDAP 等的临时故障反而让攻击者获得了访问权。凡是在 mosquitto 上部署了认证插件的部署点均处于风险之中。2.2 返回值语义MOSQ_ERR_UNKNOWN是什么在 include/mosquitto/defs.h 中定义了该错误码MOSQ_ERR_UNKNOWN 13,插件接口头文件 include/mosquitto/broker_plugin.h 对其语义有明确注释——应用特定错误application specific error。也就是说当插件内部出现它自身无法归类到其他错误码的故障数据库连接失败、配置缺失、内部异常时应返回MOSQ_ERR_UNKNOWN。它绝不代表认证通过。2.3 修复方向与源码中的错误码约定本次修复的要点是插件返回应用错误时必须拒绝客户端访问而不是放行。这与当前仓库源码中MOSQ_ERR_UNKNOWN的普遍用法一致——它被广泛用于表示发生了某种错误而非成功src/plugin_init.c 中多处return MOSQ_ERR_UNKNOWN;用于插件初始化参数校验失败等场景src/plugin_v2.c、src/plugin_v3.c、src/plugin_v4.c 中在插件函数签名缺失、无法加载mosquitto_auth_acl_check()等函数时报出MOSQ_ERR_UNKNOWNsrc/psk_file.c 在 PSK 文件读取失败时返回MOSQ_ERR_UNKNOWNsrc/conf.c 在配置解析失败时返回MOSQ_ERR_UNKNOWN。从这些实现可以看出一个通用约定MOSQ_ERR_UNKNOWN代表插件/子系统内部出错任何把该返回值当作成功MOSQ_ERR_SUCCESS处理的代码路径都是危险的。当前 Broker 的认证与 ACL 判断逻辑src/plugin_acl_check.c已经非常明确地区分了三类结果MOSQ_ERR_PLUGIN_DEFER插件不处理该检查交由后续逻辑最终会退化为拒绝MOSQ_ERR_PLUGIN_IGNORE视同插件不存在其余返回值含MOSQ_ERR_UNKNOWN、MOSQ_ERR_ACL_DENIED等直接作为最终结果返回其中任何非成功码都意味着拒绝。这正是 1.3.2 修复确立的原则认证/授权检查中只有明确返回成功才允许放行一切错误码包括应用错误都按拒绝处理。2.4 升级排查建议立即升级到包含该修复的版本尤其是生产环境部署了auth_plugin的场景检查插件代码中所有return MOSQ_ERR_UNKNOWN;路径确认后端异常如数据库不可用时插件不会误报成功在插件内对后端依赖数据库连接、缓存等做好健康检查与快速失败缩短认证失败窗口结合 Broker 日志观察认证失败原因码确认错误被正确记录。三、Broker 修复逐项解读与源码佐证3.1 桥接BridgeTLS 默认校验证书发布说明Ensure that bridges verify certificates by default when using TLS.使用 TLS 时桥接默认校验证书。在 src/conf.c 中可以看到bridge_insecure配置项的处理逻辑}else if(!strcmp(token, bridge_insecure)){ ... if(conf__parse_bool(token, bridge_insecure, cur_bridge-tls_insecure, saveptr)){ return MOSQ_ERR_INVAL; } if(cur_bridge-tls_insecure){ log__printf(NULL, MOSQ_LOG_WARNING, Warning: Bridge %s using insecure mode., cur_bridge-name); }即证书校验默认开启只有显式配置bridge_insecure true才会跳过校验并在启动日志中输出 Bridge xxx using insecure mode. 警告。该标志在 src/bridge.c 被复制到桥接的新连接上下文new_context-tls_insecure bridge-tls_insecure;并在 src/mosquitto_broker_internal.h 中作为struct mosquitto的成员参与 TLS 握手行为。1.3.2 之前存在某些路径默认不校验证书的缺陷本次修复统一为默认校验。实操要点桥接对端使用自签名证书时应在桥接配置中正确设置bridge_cafile/bridge_capath见 src/conf.c把 CA 证书提供给本地 Broker仅在可控内网、明确知道风险时才设置bridge_insecure true并留意启动时的警告日志双向认证场景还需配置bridge_certfile与bridge_keyfile见 src/conf.c。3.2 修复模式 ACL 崩溃%u与匿名客户端发布说明Fix possible crash when using pattern ACLs that do not include a %u and clients that connect without a username.修复使用不包含%u的模式 ACL且客户端未携带用户名连接时可能崩溃的问题。模式 ACL 中的%c客户端 ID与%u用户名占位符的展开逻辑位于 libcommon/topic_common.c 的topic_matches_sub()中if(match_patterns (lastchar NULL || lastchar[0] /) sub[0] % (sub[1] c || sub[1] u) (sub[2] / || sub[2] \0) ){ if(sub[1] c){ pattern_check clientid; }else{ pattern_check username; } if(pattern_check NULL || pattern_check[0] \0){ return MOSQ_ERR_SUCCESS; } ...注意这里对pattern_check NULL如匿名客户端无用户名的判空保护当 ACL 模式中没有%u、而又需要对无用户名的客户端做匹配时旧版本存在空指针解引用的崩溃风险当前实现则安全地返回不匹配。此外 src/plugin_acl_check.c 中的acl__pre_check()还提供了deny_special_chars配置可拒绝用户名/客户端 ID 中包含、#、/的客户端防止基于模式的注入攻击。实操要点编写 ACL 文件时若主题模式中包含%u应意识到匿名客户端无用户名的匹配行为需要给匿名客户端授权时应使用明确的用户段如user指令配合空用户名而非依赖%u展开升级后应回归测试匿名 模式 ACL组合确认不再崩溃且行为符合预期。3.3 修复$开头主题的订阅被误删发布说明Fix subscriptions being deleted when clients subscribed to a topic beginning with a $ but that is not $SYS.修复客户端订阅以$开头、但不是$SYS的主题时订阅被错误删除的问题。MQTT 规范规定$开头的主题为系统保留主题$SYS尤其特殊。当前 src/plugin_acl_check.c 的acl__check_dollar()对$开头主题做了分类处理$SYS仅允许桥接状态主题$SYS/broker/connection//state的写入订阅/读取按 ACL 判断$share共享订阅仅允许 SUBSCRIBE/UNSUBSCRIBE其他$开头主题先放行defer交由后续实际 ACL 检查决定。1.3.2 之前非$SYS的$主题在订阅处理中存在被误删的缺陷修复后订阅生命周期与 ACL 判定分离$开头但非$SYS的主题订阅不再被无端清理。3.4 持久会话客户端重连时重新校验队列消息 ACL发布说明When a durable client reconnects, its queued messages are now checked against ACLs in case of a change in username/ACL state since it last connected.持久客户端重连时其排队消息会重新接受 ACL 校验以防自上次连接以来用户名/ACL 状态发生变化。这与当前 src/plugin_public.c 中check_subscription_acls()的逻辑同源——在会话到期/断开时逐条检查订阅是否仍被授权/* Check to see whether durable clients still have rights to their subscriptions. */ static void check_subscription_acls(struct mosquitto *context) { ... rc mosquitto_acl_check(context, context-subs[i]-topic_filter, 0, NULL, 0, false, NULL, MOSQ_ACL_SUBSCRIBE); if(rc ! MOSQ_ERR_SUCCESS){ sub__remove(context, context-subs[i]-topic_filter, reason); } ... }而 ACL 检查的入口mosquitto_acl_check()src/plugin_acl_check.c会被以下关键路径调用构成发布前、投递前、订阅时的多重把关发布时src/handle_publish.c订阅时src/handle_subscribe.c退订时src/handle_unsubscribe.c投递给订阅者时src/subs.c、src/database.c保留消息读取时src/retain.c。1.3.2 的修复让离线排队消息也纳入这一机制客户端重连时其队列中的消息按当时的用户名/ACL 状态重新判定杜绝了先授权后吊销场景下的越权投递。3.5 匿名客户端不再因 SIGHUP 被意外断开发布说明Anonymous clients are no longer accidentally disconnected from the broker after a SIGHUP.SIGHUP 重载配置后匿名客户端不再被意外断开。该缺陷属于配置重载路径上的状态机问题修复目标是保证kill -HUP pid触发配置重载时匿名会话无用户名与认证会话享有同等生命周期管理。升级后建议做如下回归验证建立匿名连接 → 修改配置 → 发送 SIGHUP → 确认原连接保持存活。3.6 修复延迟消息相关的 bug #1324411发布说明Fix bug #1324411, which could have had unexpected consequences for delayed messages in rare circumstances.修复 bug #1324411在极少数情况下可能对延迟消息产生意外影响。该修复与遗嘱延迟/会话过期等时间驱动机制相关属于防御性修复。对使用 MQTT 延迟投递或遗嘱延迟will_delay特性的用户升级 1.3.2 可消除该边界问题。仓库中对应的延时处理基础设施可见 src/will_delay.c 与 src/session_expiry.c。四、客户端库修复解读4.1 修复主题匹配边界用例发布说明Fix topic matching edge case.主题匹配核心实现位于 libcommon/topic_common.c对外暴露的接口包括mosquitto_topic_matches_sub()libcommon/topic_common.c标准订阅过滤匹配mosquitto_topic_matches_sub_with_pattern()libcommon/topic_common.c支持%c/%u模式的匹配mosquitto_topic_matches_sub2()libcommon/topic_common.c长度受限的匹配。1.3.2 修复的是诸如$前缀规则、/#通配符组合等边界情况下的错误匹配。如果你在客户端程序中直接调用这些 API 做本地主题校验升级后应补充覆盖$主题、连续、#收尾等用例的测试。4.2 修复线程接口调用mosquitto_disconnect()后的回调死锁发布说明Fix callback deadlocks after calling mosquitto_disconnect(), when using the threaded interfaces. Closes bug #1313725.使用mosquitto_loop_start()/mosquitto_loop_stop()等线程化接口时旧版本在回调中调用mosquitto_disconnect()可能造成互斥锁重入导致的死锁。该问题的根源在于回调执行上下文与网络线程持有同一把锁。修复后回调中主动断开连接是安全的。相关线程化基础设施见 lib/thread_mosq.c。实操要点如果你在回调如on_message、on_connect中做过条件性断连1.3.2 是值得关注的安全升级同时仍建议在回调中避免长时间阻塞操作以减少对网络线程的影响。4.3 修复 CMake 构建下的 SRV 支持发布说明Fix SRV support when building with CMake.SRVDNS SRV 记录支持在 lib/CMakeLists.txt 中由WITH_SRV选项控制if(WITH_SRV) ... add_definitions(-DWITH_SRV) endif()对应实现位于 lib/srv_mosq.c。1.3.2 修复了 CMake 构建时 SRV 支持未正确编译/链接的问题。注意SRV 支持依赖 c-ares 库且默认情况下WITH_SRV可能未开启——使用 CMake 构建且需要 SRV 解析的部署请确认构建选项与链接库均已正确配置。五、构建与安装改进$(STRIP)与交叉编译发布说明Use $(STRIP) for stripping binaries when installing, to allow easier cross compilation.安装时使用$(STRIP)剥离二进制便于交叉编译。此前安装阶段对二进制的 strip 操作可能硬编码了宿主机的strip工具导致交叉编译产物在安装时被错误处理。改为$(STRIP)变量后交叉编译工具链可通过环境变量传入正确的 strip 程序。相关安装逻辑可参考仓库根目录 Makefile、src/Makefile、lib/Makefile 以及 config.mk 中的变量约定。六、升级与回归测试清单结合 1.3.2 的全部修复点建议按以下清单执行升级验证关注点验证方法关联修复认证插件应用错误临时让认证后端不可用确认客户端被拒绝CONNACK 失败而非放行bug #1340782桥接 TLS配置bridge_cafile对端证书不可信时确认连接失败bridge_insecure true时确认日志出现 insecure 警告桥接证书校验模式 ACL 匿名使用含/不含%u的 ACL 文件匿名客户端订阅/发布确认不崩溃模式 ACL 崩溃$主题订阅订阅$foo/bar非$SYS重连后确认订阅保留订阅误删持久会话 ACL修改用户名权限后让持久客户端重连确认越权排队消息被拦截排队消息 ACL 复查SIGHUP匿名连接下kill -HUP确认连接存活匿名客户端误断开客户端线程断连在线程化回调中调用mosquitto_disconnect()确认无死锁bug #1313725交叉编译用工具链变量覆盖STRIP后make install确认二进制被正确剥离$(STRIP)七、总结Mosquitto 1.3.2 是一次典型的小版本、大安全发布一个错误码语义问题MOSQ_ERR_UNKNOWN被当作认证成功足以让未授权客户端穿透认证边界桥接 TLS 默认不校验证书、模式 ACL 崩溃、$主题订阅误删等缺陷则分别影响 TLS 安全、稳定性与订阅语义。对部署了认证插件或使用桥接功能的用户而言升级 1.3.2 不是可选项而是必须项。从源码视角看本次发布确立并固化的几条工程原则至今仍体现在当前仓库中认证/授权默认失败关闭fail-closed任何非成功返回值一律拒绝参见 src/plugin_acl_check.c 的判定逻辑所有访问路径统一走 ACL 检查入口发布、订阅、投递、保留消息、排队消息均在 src/plugin_acl_check.c 的mosquitto_acl_check()处把关不安全选项必须显式声明如bridge_insecure一旦开启即输出显著警告日志。理解 1.3.2 的修复逻辑不仅有助于完成本次升级更能指导你在自定义插件、桥接拓扑与 ACL 策略设计中始终守住安全底线。赞分享后端消息队列消息路由【免费下载链接】mosquittoEclipse Mosquitto - An open source MQTT broker项目地址https://gitcode.com/gh_mirrors/mos/mosquitto点击查看免费下载相关推荐Jedis 安全加固清单TLS、ACL 与 Token 认证Microsoft Entra ID完整实践Jedis 安全加固清单TLS、ACL 与 Token 认证Microsoft Entra ID完整实践 Jedis 是 Redis 官方推荐的 Java数据库缓存后端EMQX 安全加固模式下的 JWT 认证与 JWKS 端点 TLS 校验实践EMQX 安全加固模式下的 JWT 认证与 JWKS 端点 TLS 校验实践 导读 EMQX 从 7.0 起默认启用 hardened安全加固安全配置文件后端物联网消息队列通信FastAsyncWorldEdit 高级技巧如何利用懒复制和结构块实现超大范围编辑FastAsyncWorldEdit 高级技巧如何利用懒复制和结构块实现超大范围编辑 FastAsyncWorldEdit简称FAWE是一款为艺术家、建游戏开发后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考