☰
Mosquitto 2.0.0 发布解析:默认安全策略、新插件体系与迁移要点
2026/9/28 2:41:23 网站建设 项目流程
  • 物联网
  • 消息队列
  • 后端

【免费下载链接】mosquitto

Eclipse Mosquitto - An open source MQTT broker

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

2020 年 12 月 3 日,Eclipse Mosquitto 项目正式发布 2.0 版本。这是 Mosquitto 历史上一次带有破坏性行为变更(breaking changes)的大版本升级,broker 的安全默认值、监听器行为、权限模型与插件接口均发生了根本性变化。本文以官方 2.0.0 发布公告为主线,结合当前仓库源码(src/)、动态安全插件(plugins/dynamic-security/)与配置解析实现,逐项解析新特性、破坏性变更的底层逻辑、客户端库与命令行工具的新能力,并给出从 1.x 迁移到 2.0 时的实操要点。读完本文,你将能够理解 2.0 默认安全模型的工作原理、正确配置监听器与鉴权、使用动态安全插件与mosquitto_ctrl控制运行中的 broker,并掌握新插件接口与命令行客户端的新增选项。

一、2.0.0 发布概览:一次"更安全默认值"的硬升级

发布公告开宗明义地指出:2.0 是一版"big change",对 broker 存在破坏性行为变更,用户、发行版打包者与插件作者都应参考从 1.x 迁移到 2.0 的指南。迁移指南在仓库中没有单独成文,但官方公告列出的关键变更都可以在当前仓库源码中找到对应实现,本文后续章节会逐条给出源码佐证。

2.0 的核心设计理念可以概括为三点:

  • 安全默认:不再依赖旧版"默认宽松"的行为,broker 要求用户主动决策如何配置安全策略,同时更快地放弃特权(privileged access)。
  • 新插件接口:在原有认证与访问控制插件接口之上,提供能力更强、更易开发和扩展的插件体系,同时保持对既有插件的兼容(编译时需使用 2.0 头文件)。
  • 开箱即用的动态安全:内置新的动态安全插件,提供基于客户端(client)、组(group)、角色(role)的认证与访问控制,配置通过特殊主题在线管理、可热更新。

此外,broker 在高客户端数场景下的性能得到改进;新增mosquitto_ctrl工具用于控制运行中的 broker;bridge(桥接)开始支持 MQTT v5;命令行客户端获得一批小改进。

二、破坏性变更详解:升级前必须知道的行为差异

2.1 无监听器配置时默认只绑定回环地址

这是 2.0 最影响部署习惯的变更。当 broker没有配置任何 listener启动时,将只绑定到回环接口127.0.0.1和/或::1,即只有本机客户端可以连接。具体行为:

  • 直接运行mosquitto或mosquitto -p 1883:绑定回环接口。
  • 使用不含任何 listener 的配置文件运行:绑定回环接口的 1883 端口。
  • 配置文件中定义了 listener:默认绑定0.0.0.0/::(所有接口),仍可显式绑定指定地址。
  • 若以mosquitto -c mosquitto.conf -p 1884运行,且配置文件中已定义 listener,则命令行-p指定的端口会被忽略,不会为其创建监听器。

该逻辑在源码中有明确实现。listeners__start()在 src/listeners.c#L228-L244 中判断db.config->local_only:为真时调用listeners__start_local_only(),在 src/listeners.c#L181-L225 中向127.0.0.1与::1的 1883 端口(或命令行-p指定的端口)各添加一个监听器,并打印警告:

Starting in local only mode. Connections will only be possible from clients running on this machine. Create a configuration file which defines a listener to allow remote access.

而local_only标志由配置解析驱动:config->local_only = true是 src/conf.c#L251 中的默认值,一旦配置文件中出现 listener 定义,src/conf.c#L1166、src/conf.c#L1705、src/conf.c#L2102 等位置会将其置为false。

迁移要点:若需要远程访问,必须显式创建配置文件并定义 listener,例如:

listener 1883 0.0.0.0

2.2 所有监听器默认allow_anonymous false

2.0 中所有 listener 的匿名访问默认被禁用,除非在配置文件中显式设置allow_anonymous true。这意味着配置 listener 时,用户必须二选一:配置某种认证与访问控制方法,或显式开启匿名。唯一例外是 broker 在未配置 listener 的"本地模式"下运行时,匿名连接被允许(因为只监听回环,风险可控)。

该逻辑在配置读取的收尾阶段实现。config__read()在 src/conf.c#L740-L756 中:

  • 若local_only == true,直接设置allow_anonymous = true;
  • 否则,在per_listener_settings模式下遍历各 listener,把仍处于未显式设置状态(-1)的 listener 的allow_anonymous置为false;非 per-listener 模式下则把全局默认置为false。

配置文件语法示例:

listener 1883 0.0.0.0 allow_anonymous false password_file /etc/mosquitto/passwd

2.3 root 启动时更早地放弃特权

在类 Unix 系统上以 root 运行 Mosquitto 时,2.0 在读取配置文件之后立即尝试降权,而不是像旧版那样等到 listener(及 TLS 证书)和日志启动之后才降权。带来的后果:

  • 除非用户显式(且不推荐)配置以 root 运行,客户端将永远无法连接到以 root 运行的 broker;
  • broker 需要访问的所有路径(配置文件、持久化文件、日志、TLS 证书等)都必须对降权后的非特权用户可读;
  • 使用 Let's Encrypt 证书的用户需要额外处理,使 Mosquitto 能访问证书文件,仓库提供了示例部署续期钩子脚本 misc/letsencrypt/mosquitto-copy.sh;
  • 降权目标用户按可用性依次为:配置文件中指定的用户、mosquitto、nobody。

降权实现位于 src/mosquitto.c#L130-L219 的drop_privileges():它在geteuid() == 0时执行setgid/setuid,若配置的用户不存在则回退到nobody(src/mosquitto.c#L181-L191),并支持 Docker 常见的PUID/PGID环境变量映射(src/mosquitto.c#L146-L177);在 Snap 环境下(环境变量SNAP_NAME为mosquitto)则跳过降权(src/mosquitto.c#L140-L144)。调用时机位于 src/mosquitto.c#L390,即配置读取之后、listener 启动之前。

迁移要点:以 root 安装运行时,请确认以下路径对mosquitto用户可读(必要时可写):配置文件、持久化文件目录、日志目录、TLS 证书与私钥、pid_file路径。

2.4pid_file总是写入

pid_file选项现在无论是否使用-d参数,都会尝试写入 pid 文件。对应实现为pid__write()(src/mosquitto.c#L260-L275),它在db.config->pid_file非空时无条件执行fopen并写入进程号。

2.5tls_version语义:从"精确版本"改为"最低版本"

tls_version选项从指定精确TLS 协议版本,改为指定最低允许的 TLS 协议版本(对应 GitHub issue #1258)。也就是说,设置tls_version tlsv1.2表示允许 TLS 1.2 及更高版本,而不是强制恰好使用 TLS 1.2。该选项在 src/conf.c#L2310-L2314 中解析(bridge_tls_version在 src/conf.c#L1457),且不支持热重载(reload 时被跳过)。

2.6max_queued_messages默认值提升并覆盖 QoS 0

max_queued_messages默认值从 100 提高到 1000(对应 issue #1258 之外的 #265 相关讨论),并且当客户端在线时也适用于 QoS 0 消息。默认值在 src/conf.c#L305 中设置(config->max_queued_messages = 1000),解析逻辑在 src/conf.c#L1989-L1992。其生效逻辑可在 src/database.c#L60-L133 中看到:在计算入队配额时区分在线(inflight)与离线(queued)两条路径,src/handle_publish.c#L354 在out_packet_count >= max_queued_messages时拒绝继续入队。

2.7 客户端默认加载系统 CA 证书

mosquitto_sub、mosquitto_pub、mosquitto_rr在使用-L mqtts://...时,或端口设为 8883 且未加载其他 CA 证书时,默认加载操作系统提供的 CA 证书(对应 issue #1824)。

2.8 依赖要求

最低支持的 libwebsockets 版本提升到 2.4.0。

三、新插件接口:更强能力、更低开发门槛

2.0 引入了超越原有认证/ACL 插件接口的新插件体系。新接口在保留旧插件兼容性的同时,提供了更多插件能力。从仓库源码可以看到,2.0 的插件事件处理已经按功能拆分到独立文件,包括:

  • src/plugin_auth.c、src/plugin_acl_check.c:认证与 ACL 检查;
  • src/plugin_message.c:消息收发钩子;
  • src/plugin_subscribe.c、src/plugin_unsubscribe.c:订阅/退订钩子;
  • src/plugin_connect.c、src/plugin_disconnect.c:连接生命周期事件;
  • src/plugin_persist.c、src/plugin_tick.c:持久化与周期性 tick;
  • src/plugin_psk_key.c、src/plugin_extended_auth.c:PSK 密钥与扩展认证。

插件 API 定义可参考 include/mosquitto_broker.h 与 include/mosquitto_plugin.h。仓库中的插件示例集中在 plugins/examples/,覆盖了按环境变量鉴权(auth-by-env)、按 IP 鉴权(auth-by-ip)、按主题限制(topic-jail)、消息载荷修改(payload-modification)、连接状态事件(connection-state)、延迟认证(delayed-auth)等常见场景,是学习新插件接口的最佳起点。

四、动态安全插件:客户端/组/角色的在线访问控制

2.0 内置了一个全新的动态安全插件,位于 plugins/dynamic-security/,提供基于客户端、组、角色的认证与访问控制。其核心特点:

  • 配置在线管理:通过特殊的$CONTROL主题以 JSON 命令形式下发配置,broker 运行期间可随时更新;
  • 灵活直接:为 broker 访问控制提供灵活且直观的配置方式;
  • 默认角色:插件初始化时会预置两个管理角色——broker-admin(授予管理 broker 通用配置的$CONTROL/broker/#权限)与dynsec-admin(授予管理客户端/组/角色的$CONTROL/dynamic-security/#权限),见 plugins/dynamic-security/config_init.c#L508-L509;
  • $CONTROL 主题保护:ACL 检查逻辑对$CONTROL前缀主题不做"fall through"放行,必须显式授权(plugins/dynamic-security/acl.c#L244-L245)。

官方 README(plugins/dynamic-security/README.md)说明:JSON 命令发布到类似$CONTROL/<feature>/v1的主题。仓库还提供了完整的测试套件 test/broker/14-dynsec-*.py,覆盖默认访问、匿名组、客户端/组/角色管理、ACL、通配符、禁用客户端、配置初始化等场景,可作为理解插件行为的活文档。

五、mosquitto_ctrl:控制运行中的 broker

新增工具mosquitto_ctrl(源码在 apps/mosquitto_ctrl/)用于控制运行中的 broker。2.0 中它的能力局限于控制动态安全插件(对应子命令 apps/mosquitto_ctrl/dynsec.c、apps/mosquitto_ctrl/dynsec_client.c 等),后续版本会扩展到更多功能。典型用法是与动态安全插件配合,通过$CONTROL/dynamic-security/v1主题执行createClient、createRole、createGroup、setClientPermissions等 JSON 管理命令。

六、Broker 新特性详解

6.1 桥接(Bridge)能力增强

  • MQTT v5 支持:bridge 开始支持 MQTT v5;
  • bridge_outgoing_retain:允许完全禁用桥接出站消息的 retain 位,在桥接到 Amazon、Google 等不允许 retain 的平台时非常有用。解析见 src/conf.c#L1309-L1312;
  • MQTT v5 retain-available 属性:处理 v5 桥中"retain-available"为 false 的情形;
  • 协议回退:允许 MQTT v5.0 出站桥在连接仅支持 v3.x 的 broker 时回退到 MQTT v3.1.1;
  • bridge_max_packet_size(issue #265):限制桥接消息包大小,解析见 src/conf.c#L1287-L1290;
  • bridge_bind_address(issue #1311):为桥接连接指定绑定地址,解析见 src/conf.c#L1226-L1229;
  • v5 属性遵循:bridge 遵循 MQTT v5 的 server-keepalive,并支持 maximum-qos 属性。

6.2 TLS 与密码学

  • ciphers_tls1.3(issue #1825):允许设置 TLS 1.3 加密套件,解析见 src/conf.c#L1506-L1512;
  • 证书加载方式变更:启用基于证书的 TLS 加密现在通过certfile和keyfile,而不是capath或cafile;
  • SIGHUP 重载证书:服务端 TLS 证书在收到 SIGHUP 信号时会重新加载;
  • PBKDF2-SHA512:密码哈希新增 PBKDF2-SHA512 支持,对应实现可参考 common/password_mosq.c。

6.3 运行与监听

  • Unix domain socket 监听器:支持 Unix 域套接字作为 listener;
  • 降权回退:以 root 运行时,若降权到mosquitto用户失败,则尝试nobody,减轻自行安装用户的负担;
  • DLT 日志:log_dest dlt可在运行时配置(issue #1735);
  • receive-maximum:broker 在 MQTT v5 CONNACK 中发送 receive-maximum 属性;
  • deny ACL 类型(issue #1611):ACL 新增deny类型,可显式拒绝;
  • per_listener 持久化修复:修复了重载持久化文件且启用per_listener_settings true时 listener 与客户端关联丢失的问题(issue #1891)。

6.4 新增插件 API 函数

  • mosquitto_plugin_publish():插件可直接发布消息;
  • mosquitto_client_protocol_version():插件可判断客户端使用的 MQTT 协议版本;
  • mosquitto_kick_client_by_clientid()/mosquitto_kick_client_by_username():插件可主动断开客户端;
  • 支持在插件中处理$CONTROL/主题;
  • v5 插件 ACL 检查支持控制 UNSUBSCRIBE 调用。

七、Broker 修复要点

  • 对无效的 PUBLISH、SUBSCRIBE、UNSUBSCRIBE 包发送带malformed-packet原因码的 DISCONNECT;
  • 明确mosquitto_client_certificate()使用后必须调用X509_free()(issue #1842);
  • 修复桥接 socket 出错时未从 socket 哈希表移除的问题(issue #1897);
  • mosquitto_passwd现在禁止密码中包含:字符(issue #1833);
  • 修复log_timestamp_format不适用于log_dest topic的问题(issue #1862);
  • 修复 Windows 上插件加载失败时的崩溃(issue #1866)与 Windows 文件日志问题(issue #1880);
  • 配置文件指向目录时报错(issue #1814);
  • 修复notifications_local_only true时 bridge 错误设置 Will 以管理远端通知的问题(issue #1902);
  • 新连接日志现在记录客户端端口(issue #1911)。

八、客户端库(libmosquitto)特性与修复

8.1 特性

  • 客户端 ID 生成策略变更(issue #291):客户端不再为 v3.1.1 连接生成随机 client id,改由 broker 生成(与 v5 行为一致);
  • Unix domain socket:支持通过 Unix 域套接字连接 broker;
  • 属性 API:新增mosquitto_property_identifier()、mosquitto_property_identifier_to_string()、mosquitto_property_next(),用于获取属性整数标识、转换属性名、遍历属性列表;
  • MOSQ_OPT_TCP_NODELAY(issue #1526):允许禁用 Nagle 算法;
  • mosquitto_ssl_get():客户端可取得 SSL 结构做额外校验;
  • MOSQ_OPT_BIND_ADDRESS:可独立于mosquitto_connect*()设置绑定地址;
  • MOSQ_OPT_TLS_USE_OS_CERTS:指示客户端加载并信任操作系统提供的 CA 证书。

8.2 修复

  • 修复重连时发送配额(send quota)被错误重置(issue #1822);
  • 在日志互斥锁初始化前不再使用日志(issue #1819);
  • 修复 OS X 上缺失mach/mach_time.h头文件(issue #1831);
  • 修复自动重连时未发送 CONNECT 属性(issue #1846)。

九、命令行客户端(mosquitto_pub / mosquitto_sub / mosquitto_rr)新能力

9.1 通用能力

  • --version:所有客户端支持输出版本号;
  • --nodelay:启用MOSQ_OPT_TCP_NODELAY;
  • -x:便捷设置 MQTT v5 的 session-expiry-interval 属性;
  • --tls-use-os-certs:显式使用操作系统 CA 证书;
  • Unix 域套接字:通过--unix参数连接;
  • 超时返回码 27(issue #275):mosquitto_sub -W <secs>与mosquitto_rr -W <secs>超时后返回 27。

9.2 JSON 输出

  • 使用 cJSON 库生成 JSON 输出(可用时)(issue #1222);
  • mosquitto_sub/mosquitto_rr的 JSON 输出支持 MQTT v5 属性信息(issue #1416);
  • 新增--pretty选项,控制 JSON 输出是否格式化;
  • 非 JSON 模式下也支持 v5 属性打印。

9.3 mosquitto_sub 专属改进

  • 固定列宽输出:支持字段宽度与精度的格式说明符,便于对齐表格化输出;
  • --random-filter:按比例随机过滤打印收到的消息,便于在不逐条查看的情况下观察主题整体行为;
  • 时间戳格式:%j与%J时间戳改为 ISO 8601 兼容格式。

9.4 修复

  • mosquitto_sub在全部订阅被拒绝时退出;
  • mosquitto_pub使用-f发送 0 长度文件不再报错;
  • 修复mosquitto_rr中-e与-t参数的描述(issue #1881);
  • mosquitto_sub在 Windows 上使用%U选项时以错误退出而非静默退出(issue #1908)。

十、从 1.x 迁移到 2.0 的检查清单

综合官方发布公告与上文源码分析,从 1.x 升级到 2.0 时应按如下顺序核查:

  1. 监听器:无 listener 的配置默认只监听回环接口;远程访问必须显式配置 listener;命令行-p与配置文件 listener 同时存在时命令行端口被忽略。
  2. 匿名访问:所有 listener 默认拒绝匿名连接,需配置认证/ACL 或显式allow_anonymous true。
  3. 权限与路径:root 启动会在读取配置后立即降权(依次尝试配置用户、mosquitto、nobody),确保证书、持久化文件、日志等对非特权用户可访问;Let's Encrypt 证书可参考 misc/letsencrypt/mosquitto-copy.sh。
  4. TLS:tls_version语义变为"最低版本";证书启用改走certfile/keyfile;libwebsockets 最低版本升至 2.4.0。
  5. 队列与持久化:max_queued_messages默认 1000 且覆盖在线 QoS 0;pid_file无论是否-d都会写入。
  6. 插件:既有插件需用 2.0 头文件重新编译并核对新接口;新项目建议直接使用动态安全插件或按 plugins/examples/ 的新接口编写。
  7. 客户端:客户端不再为 v3.1.1 生成随机 client id;CA 证书默认加载策略变化,注意--tls-use-os-certs与MOSQ_OPT_TLS_USE_OS_CERTS的使用。

完整的版本变更历史可进一步查阅仓库根目录的 ChangeLog.txt,动态安全插件的配置命令与示例见 plugins/dynamic-security/README.md,相应的集成测试可参考 test/broker/14-dynsec-acl.py 等用例。在动手升级前,建议先在测试环境用 2.0 配置逐项验证上述行为,再应用到生产 broker。

  • 物联网
  • 消息队列
  • 后端

【免费下载链接】mosquitto

Eclipse Mosquitto - An open source MQTT broker

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

相关推荐

上一篇:Hammerspoon 日志基础设施探秘:CocoaLumberjack 3.8.5 变更日志全解
下一篇:3个步骤解决Vuls日志爆炸难题:从磁盘告警到90%空间节省的实战方案

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询