news 2026/9/26 2:33:50

Mosquitto 安全公告深度解析:CVE-2017-7650 Pattern 型 ACL 绕过漏洞的原理与修复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mosquitto 安全公告深度解析:CVE-2017-7650 Pattern 型 ACL 绕过漏洞的原理与修复
  • 物联网
  • 消息队列
  • 后端
  • 网络/通信

【免费下载链接】mosquitto

Eclipse Mosquitto - An open source MQTT broker

项目地址:https://gitcode.com/gh_mirrors/mo/mosquitto
点击查看免费下载

本篇文章以 Eclipse Mosquitto 官方安全公告(security-advisory-cve-2017-7650)为骨架,结合当前仓库源码(src/security_default.c、src/plugin_acl_check.c、lib/util_topic.c)与配置示例(aclfile.example、mosquitto.conf),完整还原 CVE-2017-7650 的成因、危害、修复方案及当前实现中的纵深防护逻辑。读者读完后,将能准确理解 Mosquitto Pattern 型 ACL 的匹配机制,识别并规避同类绕过风险,并掌握 1.4.12 修复版本中针对危险用户名/客户端 ID 的访问限制策略。

一、漏洞总览:什么是 CVE-2017-7650

CVE-2017-7650 是 Mosquitto 历史上一个与**基于模式(Pattern)的访问控制列表(ACL)**相关的安全漏洞,影响0.15 至 1.4.11(含)的所有版本。

漏洞的核心危害在于:客户端将自身的 username(用户名)或 client id(客户端标识)设置为#或+时,可以绕过 Pattern 型 ACL 的限制,从而访问本无权访问的 MQTT 主题。由于 MQTT 的#与+分别是"多层通配符"与"单层通配符",它们在主题过滤器中具有特殊语义,而当它们出现在 username / client id 中并被拼入 Pattern ACL 的检查路径时,会破坏 ACL 匹配的预期语义,导致权限判定被绕过。

公告同时指出:同样的缺陷可能存在于第三方认证/访问控制插件中(即使用 Mosquitto 插件接口实现 ACL 判断的插件,若直接以%c/%u方式拼装主题后再做通配匹配,同样面临被#/+注入的风险)。

漏洞仅在使用Pattern 型 ACL(或可能使用第三方插件)的部署场景下才会实际触发;不使用 Pattern ACL 的默认配置不受影响。该漏洞由 HackerDom CTF 战队的 Artem Zinenko 发现并负责任地报告,已在Mosquitto 1.4.12中修复,官方同时为旧版本提供了补丁。

二、前置知识:Mosquitto 的 ACL 与 Pattern 型 ACL

要理解漏洞,先要理解 Mosquitto 的访问控制体系。Mosquitto 的 ACL 定义在acl_file指定的文件中(对应配置项acl_file),支持三种粒度:

  1. 匿名/全局主题规则:文件开头的topic行,作用于所有匿名客户端;
  2. 用户专属规则:user <username>行之后的topic行,只作用于指定用户;
  3. Pattern(模式替换)规则:pattern行,使用%c(客户端 ID)与%u(用户名)做占位符,对所有客户端生效。

官方示例文件 aclfile.example 完整展示了这三种写法:

# This affects access control for clients with no username. topic read $SYS/# # This only affects clients with username "roger". user roger topic foo/bar # This affects all clients. pattern write $SYS/broker/connection/%c/state

其中最后一行pattern write $SYS/broker/connection/%c/state的含义是:允许任意客户端(以其 client id 替换%c)向$SYS/broker/connection/<client-id>/state主题写入连接状态消息——这也是官方推荐的 bridge 连接消息授权写法。

Pattern 语法的官方约束

mosquitto.conf 中对 Pattern ACL 的语法做了完整说明:

  • 可用占位符:%c匹配客户端 ID,%u匹配用户名;
  • 替换占位符必须是主题层级中唯一的文本(即%c/%u必须独占一个 topic level,不能与其它字符拼接,如foo%c属于非法用法);
  • 语法形式与topic关键字相同,只是关键字换成pattern:
    • pattern [read|write|readwrite] <topic>
    • 示例:pattern write sensor/%u/data(允许各用户向自己的sensor/<username>/data写数据)
  • Pattern ACL 对所有用户生效,即使前面已经定义了user规则;
  • deny型规则(topic ... deny或pattern ... deny)优先于放行规则处理。

在源码层面,Pattern 规则的解析与存储由 src/security_default.c 中的add__acl_pattern()完成:函数会统计该 pattern 中包含的%c(acl->ccount)与%u(acl->ucount)出现次数,用于后续匹配时判断是否需要替换;若一条 pattern 既不含%c也不含%u,会打印警告日志。同时,deny(MOSQ_ACL_NONE)型 ACL 会被插入到放行型 ACL 链表头部,保证"先否定、后放行"的判定顺序。

三、漏洞原理深度剖析:#与+如何绕过 Pattern ACL

3.1 匹配替换机制

Pattern ACL 的匹配逻辑位于 src/security_default.c 的mosquitto_acl_check_default()中。核心调用是:

mosquitto_topic_matches_sub_with_pattern(acl_root->topic, ed->topic, ed->client->id, ed->client->username, &result);

该函数声明于 lib/util_topic.c,实为topic_matches_sub(sub, topic, clientid, username, true, result)的封装:先把 pattern 中的%c/%u替换为客户端真实的 client id / username,再按 MQTT 主题通配规则(+单层、#多层)进行匹配。

3.2 绕过路径:通配符注入

问题出在替换后的匹配阶段。当客户端将 username 或 client id 设置为#或+时:

  • #作为 username/client id:替换进 pattern 后,形如sensor/%u/data会变成sensor/#/data——在 MQTT 主题语义中#是"匹配剩余所有层级"的多层通配符。虽然sensor/#/data这种"#不在末级"的写法在标准订阅里不合法,但基于字符串的匹配实现中,#一旦被注入就可能使检查路径产生非预期的"匹配成功"结果,从而让客户端获得它本不该拥有的读/写权限。
  • +作为 username/client id:同理,+被替换进 pattern 后充当"匹配任意单层"的通配符,使客户端得以命中任何符合该层级结构的主题。

因此,攻击者只需要把 MQTT CONNECT 报文中的 username 或 client id 直接写成#/+,就能让 Pattern ACL 的权限判定"自我放行",实现本地或远程的越权访问。公告原话是:这类客户端可以访问它们本没有权限访问的 MQTT 主题。

3.3 影响面判定:仅限 Pattern 与插件场景

从源码可以精确确认漏洞的触发前提。在mosquitto_acl_check_default()中:

  • 若acl_file、内存 ACL 列表、pattern 列表三者皆为空,直接返回MOSQ_ERR_PLUGIN_IGNORE(src/security_default.c);
  • 仅当security_opts->acl_patterns非空时,才会进入危险字符检查与 pattern 匹配循环(src/security_default.c)。

这印证了公告的结论:只有启用 Pattern 型 ACL,或使用存在同类问题的第三方认证/访问控制插件时,漏洞才实际生效。纯topic字面量 ACL(含+/#通配符的静态规则)不受此漏洞影响——因为静态规则中的通配符是管理员明确写入的,不存在客户端可控的注入面。

此外还有一个值得注意的细节:从当前源码看,mosquitto_acl_check_default()对MOSQ_ACL_SUBSCRIBE/MOSQ_ACL_UNSUBSCRIBE直接返回成功(src/security_default.c),即订阅/退订请求不经过默认 ACL 的 pattern 检查,漏洞风险主要集中于**发布(write)与读取(read)**路径。

3.4 完整调用链

消息收发路径上的 ACL 判定统一收敛到 src/plugin_acl_check.c 的mosquitto_acl_check(),其调用链如下:

  • 发布路径:src/handle_publish.c 以MOSQ_ACL_WRITE调用;
  • 订阅路径:src/handle_subscribe.c 以MOSQ_ACL_SUBSCRIBE调用;
  • 退订路径:src/handle_unsubscribe.c 以MOSQ_ACL_UNSUBSCRIBE调用;
  • 投递/保留消息读取路径:src/database.c、src/retain.c、src/subs.c 以MOSQ_ACL_READ调用;
  • 持久化恢复场景:src/context.c。

mosquitto_acl_check()的判定顺序是:先执行插件的 ACL 检查回调(plugin__acl_check),再执行内置的默认 ACL 检查(mosquitto_acl_check_default),并处理MOSQ_ERR_PLUGIN_IGNORE(视为插件不存在)与MOSQ_ERR_PLUGIN_DEFER(延迟判定,最终按拒绝处理)两种特殊返回码。这意味着:即便内置 ACL 已修复,第三方插件若直接用%c/%u拼接后做通配匹配,仍可能单独存在同类漏洞——这正是公告特别提醒"同一问题可能存在于第三方插件"的原因。

四、官方修复方案(1.4.12):对危险用户名/客户端 ID 的访问限制

4.1 修复策略

Mosquitto 1.4.12 的修复思路是从源头切断通配符注入:对 username 或 client id 中包含#、+的客户端,直接拒绝其收发任何受 Pattern ACL 或插件检查的消息。公告明确列出的修复要点如下:

  • 修复针对客户端 username / client id 中含#、+的访问限制问题;
  • /(斜杠)也被一并列入禁用字符,因为它在主题中同样具有层级分隔的特殊语义,可能构成额外风险;
  • 受限制的客户端将不能接收或发送任何受 Pattern ACL 检查的消息,也不能收发任何受插件检查的消息。

4.2 当前仓库源码中的防护实现

虽然本仓库为后续演进版本,但防护逻辑清晰保留在 src/security_default.c 的mosquitto_acl_check_default()中。在进入 pattern 匹配循环之前,源码先做危险字符检查:

if(ed->client->username && strpbrk(ed->client->username, "+#")){ log__printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", ed->client->username); return MOSQ_ERR_ACL_DENIED; } if(ed->client->id && strpbrk(ed->client->id, "+#")){ log__printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", ed->client->id); return MOSQ_ERR_ACL_DENIED; }

这段代码的语义要点:

  • 检查对象是username 与 client id 两者,任一带+或#即拒绝;
  • 检查仅发生在 pattern ACL 存在时(外层有if(acl_root){...}包裹),与公告"仅 Pattern 场景受影响"的定位一致;
  • 拒绝时打印MOSQ_LOG_NOTICE级别日志,便于运维人员发现恶意尝试;
  • 该检查位于mosquitto_acl_check_default()内部,因此仅约束内置 ACL;插件侧仍需插件自身处理(MOSQ_ERR_PLUGIN_DEFER/MOSQ_ERR_PLUGIN_IGNORE语义详见 src/plugin_acl_check.c)。

需要说明的是:当前仓库实现中以"+#"作为危险字符集合,而 1.4.12 公告中同时提及将/列入禁用列表——两处表述存在差异,若你的部署依赖旧版行为,请以对应版本的实际源码为准。无论采用哪个字符集合,核心原则一致:任何可能被替换进 pattern 并充当通配符的字符,都必须从客户端可控字段中剔除。

4.3 插件侧的修复义务

公告特别强调"同一问题可能存在于第三方认证/访问控制插件"。从调用链看,src/plugin_acl_check.c 中插件回调先于内置 ACL 执行,且插件返回的非IGNORE/DEFER结果会直接作为最终裁决。因此:

  • 若你的插件自行实现了%c/%u替换与通配匹配,必须同样校验 username / client id 中的危险字符;
  • 若插件只是转发给内置 ACL(返回MOSQ_ERR_PLUGIN_IGNORE或MOSQ_ERR_PLUGIN_DEFER),则 1.4.12 的内置修复已足够覆盖。

五、1.4.12 版本完整修复清单

除 CVE-2017-7650 外,公告还列出了 1.4.12 在 Broker 侧修复的其它问题,供升级决策参考:

  • 修复因客户端消息在无存储消息的情况下被持久化,导致mosquitto.db损坏的问题;
  • 修复 bridge 无法正确重启的问题;
  • 修复 Windows 平台gets_quiet中的未初始化内存问题;
  • 修复非 glibc 系统上WITH_ADNS=no的构建问题;
  • 修正 README 文档;
  • 修复 OpenSSL 1.1 的弃用警告;
  • 修复重复 bridge 名称导致的段错误(segfault)问题;
  • 修复 CVE-2017-7650。

六、安全建议与缓解措施

结合公告与源码,给出如下实操建议:

  1. 立即升级:若使用 0.15–1.4.11 且启用了 Pattern ACL 或第三方 ACL 插件,应升级至 1.4.12 或更高版本;无法升级的旧版本部署,可获取官方为旧版提供的补丁。
  2. 检查配置面:确认acl_file中是否使用了pattern关键字(mosquitto.conf 提供了完整的 pattern 语法与示例),并审视第三方插件的 ACL 实现是否直接拼接%c/%u后做通配匹配。
  3. 启用日志监控:升级后,针对"dangerous username/client id"的NOTICE日志(src/security_default.c)可帮助识别正在尝试注入通配符的恶意客户端,建议接入日志告警。
  4. 纵深防御:Pattern 规则本身遵循"deny 优先于 allow"的链表排序(src/security_default.c),建议在敏感主题上显式添加deny规则,作为字符校验之外的兜底。
  5. 遵循占位符规范:编写 pattern 时务必让%c/%u独占一个主题层级(如sensor/%u/data),避免任何可能导致通配符与字面量混淆的拼接写法。

七、总结

CVE-2017-7650 是 MQTT 通配符语义与 ACL 模式替换机制相互作用下产生的典型注入类漏洞:#/+既可以是合法的客户端标识字符,也可以在 pattern 匹配时被解释为主题通配符。Mosquitto 的修复通过禁止危险字符出现在 username / client id 中,从根上消除了注入面;而当前仓库 src/security_default.c 中保留的防护代码,正是这一安全决策在长期演进中的延续。理解这一漏洞,对自行开发 MQTT 访问控制插件、或审计 Broker ACL 配置的工程师,都具有直接的参考价值。

  • 物联网
  • 消息队列
  • 后端
  • 网络/通信

【免费下载链接】mosquitto

Eclipse Mosquitto - An open source MQTT broker

项目地址:https://gitcode.com/gh_mirrors/mo/mosquitto
点击查看免费下载

相关推荐

上一篇:快速录制 macOS 系统声音:QuickRecorder 从权限到成片 5 步搞定
下一篇:gmaps性能优化:处理大规模地理数据集的10个技巧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 2:29:17

Substrate区块链开发框架:从核心原理到无分叉升级实战

1. 从“substrate”这个词说起&#xff1a;它到底是什么&#xff0c;能解决什么问题第一次看到“substrate”这个标题&#xff0c;很多人脑子里蹦出来的第一反应可能是“底层”“基底”“培养基”这类模糊概念。这个词本身确实是个跨领域的高频术语——在材料科学里它指衬底&am…

作者头像 李华
网站建设 2026/9/26 2:28:32

PostgreSQL用户与权限管理:角色、授权与默认权限实战

如果管理过任何一套正经的 PostgreSQL&#xff0c;你大概率遇到过两种经典场面&#xff1a;一是新同事在测试库上死活查不着一张表&#xff0c;你在工位上一看就知道是权限没给到位&#xff1b;二是上线前夜&#xff0c;有人来问某个账号为啥能碰生产库的数据。两个问题指向同一…

作者头像 李华
网站建设 2026/9/26 2:25:29

黑马电商后台管理系统实战:从环境搭建到前后端联调与部署

简介&#xff1a;这是一套面向前后端开发者的电商后台管理系统实战资源&#xff0c;以前端 Vue.js 与后端 Node.js 为主线&#xff0c;覆盖用户管理、商品管理、订单管理、库存管理、数据分析、权限控制等核心业务模块&#xff0c;既适合初学者理解项目结构&#xff0c;也适合有…

作者头像 李华