1.3 主题及心跳机制
MQTT 主题本质上是一个 UTF-8 编码的字符串,是 MQTT 协议进行消息路由的基础。MQTT 主题类似 URL 路径,使用斜杠 / 进行分层:
为了避免歧义且易于理解,通常不建议主题以 / 开头或结尾,例如 /chat 或 chat/。
不同于消息队列中的主题,MQTT 主题不需要提前创建。MQTT 客户端在订阅或发布时即自动的创建了主题,开发者无需再关心主题的创建,并且也不需要手动删除主题。
下图是一个简单的 MQTT 订阅与发布流程, APP 1 订阅了sensor/2/temperature 主题后,将能接收到 Sensor 2 发布到该主题的消息。
Keep Alive指定连接最大空闲时间T,当客户端检测到连接空闲时间超过T时,必须向Broker发送心跳报文PINGREQ,Broker收到心跳请求后返回心跳响应PINGRESP。若Broker超过1.5T时间没收到心跳请求则断开连接,并且投递遗嘱消息到订阅方;同样,若客户端超过一定时间仍没收到心跳响应PINGRESP则断开连接。
二、MQTT通信流程
客户端使用 TCP/IP 协议与 Broker 建立连接,可以选择使用 TLS/SSL 加密来实现安全通信。客户端提供认证信息,并指定会话类型。
客户端既可以向特定主题发布消息,也可以订阅主题以接收消息。当客户端发布消息时,它会将消息发送给 MQTT Broker;而当客户端订阅消息时,它会接收与订阅主题相关的消息。
MQTT Broker 接收发布的消息,并将这些消息转发给订阅了对应主题的客户端。它根据 QoS 等级确保消息可靠传递,并根据会话类型为断开连接的客户端存储消息。
2.1 MQTT 数据包格式
MQTT 数据包格式由三大部分组成:固定报头(Fixed Header)、可变报头(Variable Header)和有效载荷(Payload)。固定报头是所有 MQTT 报文必有的部分,包含报文类型、标志位和剩余长度字段;可变报头存在于部分报文类型中(如 CONNECT、PUBLISH、SUBSCRIBE 等),用于携带协议级控制信息;有效载荷则用于承载具体的应用数据,例如发布的消息内容或订阅的主题。MQTT 的数据包设计遵循轻量、低开销的原则,适用于物联网、移动通信等对带宽和性能敏感的场景。常见数据包结构如下图:
固定头 FixedHeader
固定包头有两个部分,分别定义了消息类型和内容长度;协议设计出于精简性和可扩展性考虑,固定头字节数不固定,第一个字节用于定义类型,第2-N个字节来定义长度。
第一个字节的高4bit 用于定义消息类型,低4位定义特定消息的相关标识(只在PUBLISH发布消息时用到) 。
固定包头剩余长度 Remaining Length
从固定报头的第二个字节开始,表示该数据包的长度,该长度不包括用于编码剩余长度的字节。
剩余长度使用可变长度编码方案进行二进制编码,每个字节低7位是有效位,所以单字节最大值127,最高位用于指示存在后续字节。因此每个字节编码128个值和一个连续位。
可变包头 Variable header
可变包头可以看作是对消息类型的补充定义,内容取决于消息类型,有些消息类型没有可变包头。
数据包体Payload
有些消息类型不需要Payload,有些类型可以作为可选部分,体现了协议的扩展性。
三、MQTT报文
3.1 MQTT服务报文
MQTTX 是一款优雅、易用的跨平台MQTT 5.0 桌面客户端,可以使用MQTTX软件进行可视化连接。
需要配置服务器名称、端口等信息,MQTT默认端口为1883,MQTTS的默认端口为8883,如图所示:
配置完成后进行抓包可以发现MQTT建立连接的过程:
点击MQTTX上面的关闭连接按钮。然后在wireshark上输入"mqtt"进行过滤。按时间排序,可以看到MQTT协议给Broker发送了一个Connect登录请求,然后,服务器回应一个ACK,表示登录成功。再双击Connect Command这条数据包,我们可以从下面窗口中看到数据包详细的十六进制字节内容。
查看Connect Ack数据包可以看到到服务器回应了"20 02 00 00",这里表示登录成功。
查看MQTT协议的 Subcribe和Publish数据包。可以看到客户端Subcribe一个topic("test/topic")
当Publisher往这个topic 推送 Payload 时,Broker 就会把 Payload 转发给定阅这个topic的Subcriber。这样就完成了整个流程。
3.2 MQTT心跳报文
客户端向MQTT服务器发送的一个控制报文,用于保持客户端与服务器之间的连接,也称为心跳报文。当客户端长时间没有发送其他类型的报文时,会定期发送PINGREQ报文来告知服务器客户端仍然在线。服务器收到PINGREQ后,会回复PINGRESP报文给客户端,以此来确认连接仍然有效。
四、MQTT攻击面分析
根据MQTT的特性,常见的攻击面就是Mosquitto和自定义的topic。如果存在未授权的情况下,组件本身的漏洞产生的点可能来自于数据流的处理、认证相关、安全配置、协议通信等方面,而topic的攻击面也不容忽视。因此,这里将MQTT相关的攻击面做一个梳理,具体如下:
4.1 身份认证缺陷
MQTT 服务器进行身份验证主要有两种方式:一种是通过用户名密码,另一种是通过客户端证书的方式。
由于大部分系统通过账号密码或匿名连接,攻击者可通过暴力破解或无需认证的方式直接连接 MQTT服务端,进而对相关Topic进行订阅或发布操作。当Topic中包含敏感数据或控制指令时,可能导致信息泄露,甚至被攻击者注入恶意指令,造成严重安全隐患。
比如CVE-2024-45722漏洞,是国内某厂商的网络设备,此设备使用MQTT协议传输数据。上面说到MQTT 服务器进行身份验证主要有两种方式:一种是通过账户密码,另一种是通过客户端证书的方式,这里采用账号密码认证,认证过程如下:
首先需要获取设备序列号(SN),然后,按如下图方式将生成的密码用作 MQTT 连接的密码。并代表该设备向MQTT 服务器进行身份验证。从而达到获取授权的
此时可通过编写python脚本实现漏洞利用,使我们能够以设备身份向MQTT代理进行身份验证。
4.2 未加密通信
MQTT 协议在未加密的情况下,通信内容以明文传输,容易被攻击者通过网络嗅探截获认证信息、业务数据或控制指令,存在较高的安全风险。为提升通信安全性,MQTTS 通过 TLS/SSL 加密通信信道,有效防止数据在传输过程中被窃听或篡改,并支持客户端与服务器的身份验证,降低中间人攻击等风险。进一步地,通过在应用层对 MQTT 消息内容进行加密,可实现端到端的数据保护,即使信道被攻破,攻击者也无法获取明文数据,从而更全面地保障敏感信息与控制指令的安全。
4.3 拒绝服务攻击
攻击者可通过构造大量无效或异常的连接请求、订阅请求及消息发布操作,持续消耗 MQTT Broker 的计算、内存及连接资源,导致服务响应缓慢甚至崩溃,影响正常业务运行。攻击者使用较高的服务质量(QoS)级别以及大负载来消耗代理的资源。例如,QoS 级别 2 要求代理存储消息直到成功传递,如果消息无法传输,这可能会导致资源耗尽。
4.4 应用程序安全漏洞
对于MQTT相关应用程序本身代码缺陷导致相关安全漏洞风险,例如CVE-2017-7296、CVE-2017-7651、CVE-2018-17614、CVE-2020-13849等漏洞。
接下来介绍CVE-2017-7651漏洞:
该漏洞是Mosquitto 1.4.14及的所有版本中都存在一个漏洞,该漏洞的利用是身份验证的客户端可以发送所提出设计的CONNECT数据包,这会导致代理使用大量内存。如果多个客户端执行此操作,则可能会出现内存不足的情况,并且系统可能会网格无响应,或者代理将被网络终止之前。
下面来简要分析下这漏洞,该漏洞出现在 Mosquitto 在处理客户端连接初期的内存分配逻辑中。mosquitto__calloc() 是 Mosquitto 自定义的内存分配函数,用于在接收客户端数据包并创建 mosquitto context 结构体时申请内存资源。
由于在漏洞版本中,mosquitto__calloc() 未对传入的 size 参数进行合理限制。攻击者可以构造异常或畸形的 MQTT 报文,使 Broker 在未进行身份认证的情况下,多次触发大规模内存分配操作,最终导致服务资源耗尽,引发拒绝服务(DoS)。
通过找到补丁提交的代码,与打补丁前的代码做对比可以发现,官方通过对分配大小进行了限制,从而修复该问题。详情见下图:
五、安全防护建议
为了降低MQTT协议环境的安全风险,企业应从协议安全加固、身份认证与访问控制、传输加密、网络流量监测四个核心方面构建系统化的防护体系,例如:
5.1 数据传输加密
建议使用MQTTS对数据传输进行加密,确保消息内容即使被中间人监听也无法被解读或篡改。
5.2 接入控制与权限划分
通过 ACL机制对不同客户端的发布和订阅行为进行细粒度控制,确保每个用户或设备仅能访问其授权的Topic,防止数据泄露或恶意注入。
5.3 部署协议代理与流量检测系统
在MQTT服务器与外部设备之间部署专用的 MQTT Proxy或网关,用于集中接入管控和协议审查。使用工业流量监测工具,识别异常流量。
5.4 安全配置与加固
应及时更新 MQTT 服务端版本,关闭不必要接口,限制连接数与消息速率,控制客户端发布订阅频率,启用日志审计并加强配置文件权限管理,以降低拒绝服务与控制劫持风险。
六、总结
在当今万物互联的趋势下,MQTT 协议广泛应用于物联网与工控场景,但其自身安全机制仍有待进一步完善。在实际使用过程中,应注意避免使用存在已知安全漏洞的版本,及时更改默认或弱口令,并合理配置认证、授权及加密通信等安全策略。在条件允许的情况下,应定期针对 MQTT 协议及其相关组件开展安全检查和风险评估,及时发现并消除潜在安全隐患,提升整体系统的安全防护能力。