本文屬於原創,轉載註明出處,歡迎關注微信小程序小白AI博客
微信公衆號小白AI
或者網站 https://xiaobaiai.net
1 前言
MQTT(MQ Telemetry Transport, MQ 遙測傳輸)。
它是一種發佈/訂閱、極其簡單和輕量級的消息傳遞協議,旨在用於受限設備和低帶寬,高延遲或不可靠的網絡。設計原則是使網絡帶寬和設備資源要求最小化,同時還要嘗試確保可靠性和一定程度的交付保證。這些原則也使該協議成爲新興的“M2M”或“物聯網”連接設備世界的理想選擇,並且適用於帶寬和電池電量極爲寶貴的移動應用。
物聯網的前景變得越來越大,尤其是 5G 的到來,各領域如車聯網、車載娛樂(AR 等)、智能電網、移動和協作機器人、智能視頻監控、智慧城市等等。
IOT ANALYTICS
機構預測到 2025 年全世界運行的物聯網設備能達到 342 億(34.2billion)。各互聯網大頭公司,如亞馬遜、微軟、阿里巴巴、騰訊、IBM 等等都推出了物聯網雲平臺。而每個雲平臺都對 MQTT 協議支持,支持直接將設備通過 MQTT 協議與他們的雲平臺對接起來。MQTT 是一個開放的協議,我們可以自己去搭建自己的雲平臺,實現定製化開發,那麼在實現 MQTT 安全上有什麼需要注意的地方呢?本文從實現了 MQTT 協議的 mosquitto broker 具體示例來講述。
2 安全實現方式
- MQTT 協議本身支持用戶名和密碼實現客戶端的身份校驗
- 使用 SSL(升級版本 TLS)對網絡數據進行加密(這與 MQTT 協議本身是無關的,會增加網絡開銷)
- 通過 Broker 配置對 Topic 的讀寫權限
- 使用授權管理插件,實現批量級用戶權限和 topic 的讀寫權限管理
2.1 使用用戶名和密碼限制連接
通過使用用戶名和密碼限制連接的方式,客戶端連接 broker 時需要設置與 broker 要求的用戶名密碼才能夠連接成功。
mosquitto.conf:
# 指定用戶名和密碼才能連接broker
allow_anonymous false
password_file {your password path}/passwdfile
密碼文件的生成:
mosquitto_passwd [ -c | -D ] passwordfile username
mosquitto_passwd -b passwordfile username password
mosquitto_passwd -U passwordfile
-b
以批處理模式運行。這允許在命令行提供密碼,這可以很方便,但應小心使用,因爲密碼將在命令行和命令歷史記錄中可見
-c
創建一個新的密碼文件,如果文件已經存在,則會覆蓋。輸入命令後,控制檯會提示輸入新建用戶的密碼,連續輸入兩次密碼後,則密碼文件創建完成
-D
從密碼文件中刪除指定的用戶
-U
此選項可用於使用哈希密碼將帶有純文本密碼的密碼文件升級/轉換爲一個密碼文件
2.2 使用 SSL(升級版本 TLS)對網絡數據進行加密
使用 TLS 對網絡數據加密,需要在配置文件中指定認證文件、密鑰文件。
mosquitto.conf:
cafile {your file path}/m2mqtt_ca.crt
certfile {your file path}/m2mqtt_srv.crt
keyfile {your file path}/m2mqtt_srv.key
如何簽發證書,查看另一篇文章“使用 TLS 和 Mosquitto Broker 實現安全通信之密鑰和證書生成”;
2.3 配置 Broker ACL
通過設置 Broker ACL,可以限制指定用戶對指定 Topic 的數據讀寫權限。
mosquitto.conf:
# 配置acl_file參數爲指定acl文件
acl_file {your file path}/aclfile
aclfile 文件內容示例:
# 如下配置會影響沒有用戶名的客戶端的訪問控制
# topic [read|write|readwrite] <topic>
topic read $SYS/#
# 如下配置會影響用戶名爲 "roger" 的訪問控制.
user roger
topic foo/bar
# 如下配置會影響所有客戶端
# pattern [read|write|readwrite] <topic>
pattern write $SYS/broker/connection/%c/state
2.4 使用授權管理插件,實現批量級用戶權限和 topic 的讀寫權限管理
使用授權管理插件 https://github.com/jpmens/mosquitto-auth-plug
該插件可以執行身份驗證(檢查用戶名/密碼)和授權(通過 ACL 授予訂閱和/或發佈特定主題的許可),通過與數據庫綁定,將身份驗證和 ACL 管理錄入數據庫,從而很方便的實現用戶身份驗證管理。該插件對數據庫 mysql 及 mongodb 支持很友好。具體怎麼使用可以參考 README。這裏僅給出 mysql 配置示例。
mosquitto.conf:
# 指定插件所需動態庫
auth_plugin /usr/mosquitto/bin/auth-plug.so
# 指定後端數據庫
auth_opt_backends mysql
# 指定數據庫主機地址
auth_opt_host localhost
# 指定數據庫訪問端口
auth_opt_port 3306
# 指定數據庫名
auth_opt_dbname your_database
# 指定數據庫訪問用戶名
auth_opt_user your_username
# 指定數據庫訪問密碼
auth_opt_pass your_passwd
# 配置身份驗證查詢語句
auth_opt_userquery select (case password_syncstatus when 'sync' then user_passwd else old_password end) as user_passwd from tbl_mqttuser where user_name='%s'
# 配置ACL驗證查詢語句
auth_opt_aclquery SELECT topic FROM tbl_mqttacls WHERE (user_name = '%s') AND (rw >= %d)
# 匿名MQTT連接時插件配置的用戶名
auth_opt_anonusername anonymouS
mysql 中 tbl_mqttuser 及 tbl_mqttacls 兩個表數據示例:
mysql> select * from tbl_mqttacls;
+--------+--------------+--------+----+
| acl_id | user_name | topic | rw |
+--------+--------------+--------+----+
| 1 | user_1 | # | 6 |
| 2 | user_2 | $SYS/# | 4 |
+--------+--------------+--------+----+
4 rows in set (0.00 sec)
mysql> select * from tbl_mqttuser;
+---------+--------------+---------------------------------------------------------------------+---------------------------------------------------------------------+---------------------+---------------------+
| user_id | user_name | user_passwd | old_password
⚠️ 注意: 對
$SYS
系統主題的權限設置需要注意讀寫權限,一般來說是不會開放寫數據權限的,否則系統主題得到的數據就不是正確的統計數據了,可能是篡改掉了的。在生產環境中一般系統主題是不會開放的。
3 總結
- 物聯網的安全尤爲重要,MQTT 作爲廣泛使用的輕量級協議,實現安全的方式有多種
- MQTT 協議本身支持用戶名和密碼實現客戶端的身份校驗
- 使用 SSL(升級版本 TLS)可以對網絡數據進行加密(這與 MQTT 協議本身是無關的,會增加網絡開銷)
- 通過 Broker 可以配置對 Topic 的讀寫權限
- 使用授權管理插件,實現批量級用戶權限和 topic 的讀寫權限管理
- 對
$SYS
系統主題的權限設置需要注意讀寫權限,一般來說是不會開放寫數據權限
4 擴展之 MQTT SYS 主題
MQTT v3.1.1
是較舊的 ISO 和 OASIS 標準,MQTT v5.0
是 OASIS 標準,該協議定義了靜態主題、必須實現的SYS
主題和非必須實現的主題。
靜態 SYS 主題: 不需要在每個$SYS
主題更新時間間隔上發送有關靜態$SYS
主題的消息,只有在訂閱了之後才發送一次。
必選主題: 每個聲稱支持$SYS
主題的代理(broker,如 mosquitto)都應支持這些主題,是每個 broker 都需要支持的。
可選主題: 代理可以選擇性實現這些主題。
必選主題和可選主題中包含靜態主題。
必選主題:
$SYS/broker/load/bytes/received
: 自代理啓動以來收到的字節總數。$SYS/broker/load/bytes/sent
: 自代理啓動以來發送的字節總數。$SYS/broker/clients/connected
: 當前連接的客戶端數$SYS/broker/clients/disconnected
: 在代理上註冊但當前已斷開連接的持久客戶端總數(禁用了 clean session)。$SYS/broker/clients/maximum
: 已連接到代理的最大活動客戶端數。僅在更新$SYS
主題樹時才計算此值,因此可能不計算短暫的客戶端連接。$SYS/broker/clients/total
: 當前已在代理上連接並註冊的持久會話的已連接和已斷開連接的客戶端總數。$SYS/broker/messages/received
: 自代理啓動以來收到的任何類型的消息總數。$SYS/broker/messages/sent
: 自代理啓動以來發送的任何類型的消息總數。$SYS/broker/messages/publish/dropped
: 由於運行中/排隊限制而刪除的發佈消息總數。$SYS/broker/messages/publish/received
: 自代理啓動以來收到的 PUBLISH 消息總數。$SYS/broker/messages/publish/sent
: 自代理啓動以來發送的 PUBLISH 消息總數。$SYS/broker/messages/retained/count
: 代理上活動的保留消息總數。$SYS/broker/subscriptions/count
: 代理上活動的訂閱總數。$SYS/broker/uptime
: 代理已聯機的時間(以秒爲單位)$SYS/broker/version
: broker 的版本。靜態主題
可選主題:
$SYS/broker/time
: 服務器上的當前時間$SYS/broker/timestamp
: 生成此特定版本的代理的時間戳。靜態主題。- …
5 參考鏈接
- https://github.com/mqtt/mqtt.github.io/wiki/SYS-Topics
- https://docs.vernemq.com/configuration/bridge
- https://www.hivemq.com/blog/why-you-shouldnt-use-sys-topics-for-monitoring/
- https://mosquitto.org/man/mosquitto-8.html
- http://mqtt.org/faq
- https://iot-analytics.com/state-of-the-iot-update-q1-q2-2018-number-of-iot-devices-now-7b/
- https://blog.teserakt.io/2019/02/25/securing-the-mosquitto-mqtt-broker/
- https://github.com/jpmens/mosquitto-auth-plug