3. 零信任下的MQTT威胁建模:Broker面临的常见攻击与数据泄露路径
威胁建模这事儿,说白了就是“假设自己已经被攻破了”,然后倒推攻击者会怎么进来、怎么搞破坏。我在做零信任架构落地时,最深的体会是:MQTT Broker 是整个物联网系统的“心脏”,但很多人只给它穿了件单薄的外衣。今天咱们就把 Broker 可能挨的刀子,一把一把摆到桌面上看。
核心观点:零信任下的威胁建模,不是找“有没有漏洞”,而是假设“一定有漏洞”,然后设计防御纵深。MQTT Broker 的威胁面集中在三个维度——通信信道、身份信任、数据访问。
3.1 中间人攻击:TLS 不是万能药
中间人攻击(MITM)是 MQTT 通信中最经典的威胁。你想想看,如果客户端和 Broker 之间的 TCP 连接是明文的,攻击者只要在同一个网段里,就能用 Wireshark 把 Topic、Payload 看得一清二楚。
我遇到过一家做智能照明的客户,他们觉得“内网很安全”,MQTT 直接跑在 1883 端口上。结果呢?办公区的 Wi-Fi 被攻破后,攻击者直接订阅了所有灯控 Topic,半夜把整栋楼的灯全打开了。嗯,这就是典型的 MITM 后果——窃听 + 篡改。
但加了 TLS 就万事大吉了吗?不一定。我记得有个项目,他们虽然启用了 TLS,但证书是自签名的,客户端代码里写了 verify=False。这跟没加密有什么区别?攻击者照样可以伪造 Broker 证书,把流量劫持到自己的恶意 Broker 上。
避坑指南:我曾经见过一个团队,为了“性能优化”把 TLS 的证书链验证关掉了。结果上线第一天就被安全团队抓了包。记住:TLS 必须做双向验证(mTLS),客户端也要验证 Broker 的证书,反之亦然。
3.2 重放攻击:时间戳 + 序列号是标配
重放攻击,说白了就是攻击者把截获的合法 MQTT 报文重新发一遍。比如你发了一条“打开车门”的指令,攻击者记下来,等你下车后再重放这条报文——车门又开了。
MQTT 协议本身没有防重放机制,这得靠应用层自己解决。我常用的方案是:在 Payload 里嵌入时间戳和单调递增的序列号。Broker 收到消息后,先检查时间戳是否在允许的窗口内(比如 ±5 秒),再检查序列号是否已经用过。
// 伪代码:防重放 Payload 结构
{
"device_id": "sensor-001",
"command": "unlock_door",
"timestamp": 1712345678,
"sequence": 42,
"signature": "HMAC-SHA256(device_secret, timestamp+sequence+command)"
}
这里有个细节:签名必须覆盖时间戳和序列号,否则攻击者可以篡改这两个字段。我在一个车联网项目里就吃过这个亏——当时只对 command 字段做了签名,结果攻击者把时间戳改成了未来值,绕过了过期检查。
3.3 未授权订阅:Topic 的“越狱”风险
未授权订阅,是 MQTT 里最容易被忽视的威胁。攻击者只要知道 Topic 命名规则,就能用任意客户端订阅敏感 Topic。比如你的设备上报体温数据,Topic 是 v1/device/{device_id}/temperature,攻击者猜出 device_id 的规律后,直接订阅 v1/device/+/temperature——所有用户的体温数据就全暴露了。
零信任的做法是:每个客户端只能订阅它被明确授权的 Topic。这需要在 Broker 层面做 ACL(访问控制列表)。我推荐用 动态 ACL,而不是静态配置。比如 EMQX 支持基于 JWT 的权限声明,客户端连接时携带 Token,Broker 从 Token 里解析出允许订阅的 Topic 列表。
| 授权方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 静态 ACL(配置文件) | 实现简单,性能高 | 变更需重启 Broker,不灵活 | 设备数量少、Topic 固定的场景 |
| 数据库 ACL(MySQL/Redis) | 支持动态变更,可审计 | 依赖外部存储,有延迟 | 中等规模,需要管理后台 |
| JWT 动态授权 | 无状态,可扩展性强 | Token 签发需额外服务 | 大规模分布式系统,零信任架构 |
个人经验:我建议在 Broker 层面开启 Topic 通配符拦截。比如禁止客户端订阅 # 或 $SYS/#,除非有特殊授权。另外,发布和订阅的权限要分开控制——很多设备只需要发布数据,根本不需要订阅任何 Topic。
3.4 设备身份伪造:不只是密码的问题
设备身份伪造,是物联网里最头疼的问题。攻击者拿到一个设备的固件,就能提取出里面的 Client ID、用户名、密码甚至证书私钥。然后他可以用这些凭证,伪装成合法设备接入 Broker。
零信任的思路是:不信任任何静态凭证。我常用的方案是 设备证书 + 动态令牌 双因子认证。设备首次注册时,颁发一个短期有效的证书(比如 7 天),同时绑定设备的硬件指纹(比如 TPM 芯片的 EK Pub)。每次连接时,Broker 不仅要验证证书,还要验证设备能否用私钥签名一个随机挑战。
这里有个坑:很多 IoT 设备没有 TPM 或 Secure Element。怎么办?我建议至少做到:Client ID 不能是纯数字序列号,要包含随机数或 HMAC 签名。比如 device_{HMAC(device_secret, timestamp)},这样攻击者即使拿到一个设备的凭证,也无法伪造其他设备的 Client ID。
我曾经踩过的坑:在一个智慧农业项目里,设备使用固定的 Client ID(比如 sensor_001)和明文密码。攻击者通过抓包拿到了密码,然后写了个脚本,用同一个 Client ID 同时连接了 100 个会话。Broker 没有做会话去重,结果所有传感器数据都被污染了。后来我们加了 Client ID 唯一性检查——同一个 Client ID 只允许一个活跃会话,新连接会踢掉旧连接。
3.5 数据泄露路径分析:从 Broker 到存储
数据泄露不只是 Broker 被攻破这一条路。我习惯画一张 数据流图,把每个环节的泄露风险标出来。下面这张 SVG 图,就是我在项目中常用的分析框架。
从这张图能看出,数据泄露不是单点问题,而是链式反应。攻击者可以从任何一个环节切入,然后横向移动。我见过最典型的案例是:攻击者先通过 Wi-Fi 嗅探拿到设备凭证(路径④),然后伪装成设备订阅了 Broker 上的管理 Topic(路径②),最后从 Broker 的日志里提取出数据库连接信息(路径③)。
3.6 威胁建模清单:实战检查项
说了这么多,最后给一份我每次做 MQTT 安全评估时都会用的检查清单。你可以直接拿去用。
- 通信层:是否启用了 mTLS?证书链验证是否强制开启?是否禁用了不安全的 TLS 版本(1.0/1.1)?
- 身份层:Client ID 是否包含防伪造机制?设备凭证是否支持动态轮换?是否做了会话唯一性检查?
- 授权层:是否启用了 Topic 级 ACL?是否禁止了通配符订阅?发布和订阅权限是否分离?
- 数据层:Payload 是否包含防重放字段(时间戳+序列号)?敏感数据是否在应用层加密?Broker 日志是否脱敏?
- 运维层:Broker 的管理接口是否暴露在公网?是否开启了审计日志?是否有异常流量告警?
我的习惯:每季度做一次威胁建模复盘,把新发现的攻击路径更新到清单里。零信任不是一次性工程,而是持续迭代的过程。你想想看,攻击者的手法在变,你的防御策略也得跟着变。