2. MQTT Broker 安全基线配置

好,咱们进入实战环节。上一章聊了威胁模型,这一章咱们直接上手——把 Broker 的「安全底线」给立住。

我个人习惯,拿到一台新 Broker 服务器,第一件事不是配功能,而是做基线加固。说白了,就是先把大门关好,再考虑屋里怎么装修。

Mosquitto 是目前最主流的开源 Broker,我就拿它当例子讲。其他 Broker 比如 EMQX、VerneMQ,思路完全一样,参数名可能不同,但原理相通。

核心原则:最小暴露原则 + 默认拒绝策略。没明确允许的,一律禁止。

2.1 监听端口绑定:别把 Broker 挂在公网上裸奔

很多新手图省事,直接 listener 1883 就完事了。结果 Broker 对全世界开放,扫描器一扫就暴露。

我在项目中遇到过一家智能家居厂商,他们的 Mosquitto 监听在 0.0.0.0:1883,没有任何 IP 限制。上线第三天就被植入了恶意订阅端,窃取了大量设备遥测数据。

正确的做法是:

# 只监听内网接口
listener 1883 192.168.1.100

# 如果需要公网访问,必须走 TLS + 认证
listener 8883 0.0.0.0

嗯,这里要注意:1883 端口永远不要暴露到公网。明文传输,谁都能抓包看内容。公网必须用 8883(TLS)或 443(WebSocket over TLS)。

端口 协议 加密 推荐场景
1883 MQTT 明文 仅内网
8883 MQTT over TLS 加密 公网/跨网络
8083 WebSocket 明文 仅内网 Web 应用
8084 WebSocket over TLS 加密 公网 Web 应用

警告:不要用 listener 1883 0.0.0.0。即使有防火墙,也建议在 Broker 层面做绑定,形成双重防护。

2.2 协议版本限制:拒绝老旧客户端

MQTT 有 3.1、3.1.1、5.0 三个主要版本。3.1 太老了,安全机制薄弱,连遗嘱消息的权限控制都不完善。

我建议只允许 3.1.1 和 5.0。怎么配?

# Mosquitto 配置
protocol_version 5            # 启用 MQTT 5.0
allow_unsafe_client_id false  # 禁止空 Client ID

# 或者用 listener 级别控制
listener 1883
protocol mqttv311

你想想看,如果允许 MQTT 3.1 的客户端接入,攻击者可以用一些老版本特有的漏洞,比如 CONNECT 报文中的恶意载荷。我曾经在渗透测试中,就利用 3.1 版本的 Clean Session 处理缺陷,让 Broker 内存泄漏,最终导致服务崩溃。

小技巧:如果业务必须兼容老旧设备,可以单独开一个监听端口给 3.1 客户端,并加上严格的 ACL 限制。别让它们跟主集群混在一起。

2.3 最大连接数控制:别让 Broker 被挤爆

连接数不限制,后果很严重。攻击者可以发起大量 CONNECT 请求,耗尽 Broker 的文件描述符和内存。

我记得有一次,一个客户的生产环境 Broker 突然挂了。查日志发现,某个 IP 在 10 秒内发起了 5000 次连接请求,直接把 Mosquitto 的默认连接池打满了。

配置方法:

# 全局最大连接数
max_connections 1000

# 每个客户端的最大连接数(MQTT 5.0 支持)
max_connections_per_client 5

# 连接速率限制(需要插件或外部工具)
# Mosquitto 本身不支持,可以用 iptables 或 nginx 前置限流

为什么是 1000?这取决于你的服务器资源。我一般按「每个连接预留 64KB 内存」来估算。1000 个连接大约需要 64MB,加上业务开销,128MB 打底。

服务器规格 建议最大连接数 备注
1C2G 500 轻量测试环境
2C4G 2000 小型生产
4C8G 5000 中型生产
8C16G+ 10000+ 大型集群

注意:连接数不是越大越好。超过硬件承载能力,Broker 会频繁 GC 甚至 OOM。设置一个合理的上限,比事后扩容更重要。

2.4 消息大小限制:防止大包攻击

MQTT 协议本身允许最大 256MB 的消息体。但你真的需要这么大吗?

攻击者可以发送一个超大 PUBLISH 报文,让 Broker 分配巨量内存来缓存。如果同时来几十个,内存直接爆掉。

我在项目中遇到过一种攻击:攻击者用 10MB 大小的消息持续发布,Broker 的 retain 消息表迅速膨胀,最终磁盘写满,服务中断。

配置方法:

# Mosquitto 配置
message_size_limit 1048576    # 限制为 1MB

# 如果使用 MQTT 5.0,还可以限制 Topic 别名大小
topic_alias_maximum 10

嗯,这里要说明一下:message_size_limit 限制的是整个 MQTT 报文,包括固定头、可变头和载荷。实际业务消息体建议控制在 256KB 以内。

经验值:物联网设备上报的数据,大部分在 1KB-10KB 之间。视频流或文件传输不应该走 MQTT,那是 HTTP 或 FTP 的事。

2.5 其他关键基线项

除了上面四个核心项,还有几个容易被忽略的点:

  • 禁止匿名访问:allow_anonymous false。这是最基本的,但很多 Demo 环境忘了关。
  • 限制 Topic 层级深度:防止攻击者用超长 Topic 路径消耗资源。Mosquitto 默认 200 层,建议改为 10-20 层。
  • 关闭 Bridge 模式:如果不需要 Broker 桥接,关掉它。Bridge 模式容易引入环路和消息风暴。
  • 日志审计:开启连接日志和 ACL 拒绝日志,方便事后溯源。
# 完整的安全基线配置示例
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl

listener 1883 192.168.1.100
protocol mqttv311
max_connections 1000
message_size_limit 1048576

listener 8883 0.0.0.0
protocol mqttv5
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
tls_version tlsv1.2

log_type all
connection_messages true
log_dest file /var/log/mosquitto/mosquitto.log

一句话总结:基线配置就是给 Broker 穿上「铠甲」——绑定内网、限制版本、控制连接、限制消息大小、关掉匿名。这五步做完,80% 的常见攻击就被挡在门外了。

MQTT Broker 安全基线配置框架 Broker 安全基线 监听端口绑定 内网 1883 / 公网 8883 协议版本限制 仅 3.1.1 / 5.0 最大连接数控制 全局 + 每客户端限流 消息大小限制 建议 ≤ 1MB 其他关键项 匿名 / Topic深度 / 日志 核心原则 最小暴露原则 + 默认拒绝策略 五步做完,阻挡 80% 常见攻击