5月31日 00:26

MQTT 通信如何保证安全?TLS、认证和 ACL 怎么搭配?

MQTT 安全不能只靠一个用户名密码。比较稳的做法是分三层:先用 TLS 保护链路,再用认证确认“谁连上来”,最后用 ACL 限制“它能发布和订阅什么主题”。如果消息本身很敏感,还要在应用层做加密或签名,因为 TLS 只保护传输过程,Broker 收到消息后仍然能看到明文。

MQTT 安全主要防什么?

MQTT 常见风险有四类:明文传输被抓包、弱口令被撞库、客户端越权订阅主题、伪造设备发送控制指令。1883 端口默认不加密,在测试环境很方便,但放到公网基本等于把账号和消息内容暴露出去。生产环境通常使用 8883 端口跑 MQTT over TLS,客户端校验 Broker 证书,避免连到假 Broker。

认证解决的是身份问题。最常见的是用户名和密码,也可以使用 JWT、OAuth2 Token 或客户端证书。用户名密码实现简单,但必须配合 TLS,否则 CONNECT 报文里的凭据可能被截获。证书认证更适合设备数量可控、生命周期长的场景,缺点是证书签发、吊销和更新都要有流程。

授权靠 ACL 落地。不要给设备订阅 # 或发布任意主题的权限,主题最好带上租户、产品、设备 ID,例如 tenant/a/device/001/up。服务端只允许设备发布自己的上行主题,只允许订阅自己的下行主题。这个规则看起来啰嗦,但能防止一个设备越权读取另一台设备的数据。

还有一个经常被忽略的点是 Client ID。很多设备 SDK 示例会写死 client1,测试时没问题,上线后多个设备互相顶号,安全排查会非常混乱。Client ID 最好和设备身份绑定,并在 Broker 侧限制同一身份的连接策略。日志里也要保留客户端 IP、用户名、Client ID、订阅主题和拒绝原因,否则出事后只能猜。

conf
listener 8883 certfile /etc/mosquitto/certs/server.crt keyfile /etc/mosquitto/certs/server.key cafile /etc/mosquitto/certs/ca.crt allow_anonymous false password_file /etc/mosquitto/passwd acl_file /etc/mosquitto/acl
bash
mosquitto_passwd -c /etc/mosquitto/passwd device001 mosquitto_pub -h broker.example.com -p 8883 --cafile ca.crt -u device001 -P 'secret' -t tenant/a/device/001/up -m '{"temp":25}'

还有一个实用做法是把安全配置分环境管理。开发环境可以使用本地 Broker 和临时账号,但预发、生产必须强制 TLS、禁止匿名、收紧 ACL,并把配置变更纳入审计。不要把 Broker 管理后台直接暴露到公网,管理端口应放在内网或 VPN 后面。安全不是一次性配置,证书过期、员工离职、设备报废都会让原本安全的系统慢慢变脆。

追问

只开 TLS 就够了吗?

不够,TLS 只能说明链路是加密的,并不能自动说明客户端有业务权限。一个合法设备如果拿到了通配符订阅权限,仍然可以看到不该看的主题。实际项目里 TLS、认证、ACL 要一起上,少一层都会留下明显缺口。取舍在于成本:内网测试可以先用用户名密码,公网和多租户环境至少要 TLS 加 ACL。

用户名密码和客户端证书怎么选?

用户名密码适合设备多、接入快、需要后台批量生成凭据的系统,运维成本低。客户端证书更适合网关、工业设备、金融终端这类安全要求高且设备数量可控的场景。证书的坑在于过期和吊销,很多事故不是加密算法不安全,而是证书到期后设备大面积掉线。选择时要看你有没有完整的证书生命周期管理能力。

ACL 规则最容易踩什么坑?

最常见的坑是主题设计太随意,后面 ACL 无法精确表达权限。比如所有设备都往 data/upload 发消息,Broker 很难区分来源,只能把鉴权压力挪到应用层。更好的做法是从第一天就把租户、产品、设备 ID 放进主题路径。边界也要注意:+ 只能匹配一级,# 必须放在末尾,误用通配符会造成越权订阅。

消息还需要端到端加密吗?

如果 Broker 本身可信,TLS 通常已经够用,因为 Broker 需要读取主题并转发消息。如果消息经过第三方云 Broker,或者内容是医疗、金融、门锁指令,就要考虑应用层加密和签名。加密会带来密钥分发、调试困难和规则引擎无法解析 payload 的代价。实际取舍是:遥测数据通常只签名或走 TLS,关键控制命令更适合加签名、防重放和短有效期。

如何发现 MQTT 安全配置有问题?

先检查 1883 是否暴露公网,再检查是否允许匿名连接和弱密码。然后用测试账号尝试订阅 #、发布到别的设备主题,看 ACL 是否真的生效。日志里要关注频繁 CONNECT 失败、异常 Client ID、短时间大量订阅等行为。很多问题不是 Broker 没有安全能力,而是默认配置太宽松,上线前没有做一次越权测试。

标签:MQTT