找回密碼
 立即註冊
惟家LINE群QRCODE
    查看: 1|回覆: 0

    Mosquitto 設定與帳號權限:不要讓 MQTT 變成安全破口

    [複製鏈接]

    !lvup!   100%

    363

    主題

    27

    回帖

    2200萬

    積分

    管理員

    積分
    22005752
    發表於 3 天前 | 顯示全部樓層 |閱讀模式
    MQTT 是很多智能家居服務的中樞。
    但它預設沒有任何安全機制,設錯的話等於把家裡的控制權開放出去。



    先講風險

    MQTT 的設計是「誰都可以訂閱、誰都可以發布」。

    如果你的 broker 開放匿名連線,而且能從外部存取:


    • 任何人可以訂閱所有主題,知道你家的一切
        (門開了、有沒有人、什麼時候出門)
    • 任何人可以發布指令,控制你的燈、開關、門鎖
    • 任何人可以刪除 MQTT Discovery 的設定,讓你的裝置全部消失


    而且完全不會留下痕跡。

    最低限度的三件事


    • 關閉匿名連線
    • 每個客戶端用不同帳號
    • 不要把 1883 埠開到公網


    完整的 mosquitto.conf
    1. # /volume1/docker/mosquitto/config/mosquitto.conf
    2. # ---------- 監聽 ----------
    3. listener 1883
    4. protocol mqtt
    5. # WebSocket(有些前端會用到)
    6. listener 9001
    7. protocol websockets
    8. # ---------- 安全 ----------
    9. allow_anonymous false
    10. password_file /mosquitto/config/passwd
    11. acl_file /mosquitto/config/acl
    12. # ---------- 持久化 ----------
    13. persistence true
    14. persistence_location /mosquitto/data/
    15. autosave_interval 1800
    16. # ---------- 日誌 ----------
    17. log_dest file /mosquitto/log/mosquitto.log
    18. log_type error
    19. log_type warning
    20. log_type notice
    21. log_type information
    22. connection_messages true
    23. log_timestamp true
    24. # ---------- 限制 ----------
    25. max_connections -1
    26. max_queued_messages 1000
    27. message_size_limit 268435456
    複製代碼

    建立帳號
    1. # 進容器
    2. sudo docker exec -it mosquitto sh
    3. # 第一個帳號用 -c(會建立新檔案,會覆蓋舊的!)
    4. mosquitto_passwd -c /mosquitto/config/passwd homeassistant
    5. # 之後的用 -b(batch,直接帶密碼)或不帶 -c
    6. mosquitto_passwd -b /mosquitto/config/passwd zigbee2mqtt 密碼
    7. mosquitto_passwd -b /mosquitto/config/passwd frigate 密碼
    8. mosquitto_passwd -b /mosquitto/config/passwd esphome 密碼
    9. exit
    10. sudo docker restart mosquitto
    複製代碼

    -c 只有第一次用。後面再用 -c 的話會把之前的帳號全部清掉。

    (這個我踩過,重建帳號的時候順手加了 -c,結果所有服務同時斷線。)



    ACL:限制每個帳號能碰哪些主題

    這是很多人跳過的一步,但它是縱深防禦的關鍵。

    建立 /mosquitto/config/acl
    1. # ---------- Home Assistant:需要全部權限 ----------
    2. user homeassistant
    3. topic readwrite #
    4. # ---------- Zigbee2MQTT:只碰自己的命名空間 ----------
    5. user zigbee2mqtt
    6. topic readwrite zigbee2mqtt/#
    7. topic write homeassistant/#
    8. # ---------- Frigate ----------
    9. user frigate
    10. topic readwrite frigate/#
    11. topic write homeassistant/#
    12. # ---------- ESPHome 裝置 ----------
    13. user esphome
    14. topic readwrite esphome/#
    15. topic write homeassistant/#
    16. # ---------- 唯讀的監控帳號 ----------
    17. user monitor
    18. topic read #
    複製代碼

    語法說明


    • read — 只能訂閱
    • write — 只能發布
    • readwrite — 都可以
    • # — 多層萬用字元(所有子主題)
    • + — 單層萬用字元


    為什麼 Z2M 需要 write homeassistant/#
    因為它要發 MQTT Discovery 的設定訊息。
    但它不需要讀,所以只給 write。

    這樣萬一 Z2M 被入侵,攻擊者也不能訂閱你其他裝置的資料。

    測試 ACL 有沒有生效
    1. # 用 frigate 帳號試著訂閱 zigbee2mqtt 的主題(應該失敗)
    2. mosquitto_sub -h 192.168.1.20 -u frigate -P 密碼 -t "zigbee2mqtt/#" -v
    3. # 日誌會顯示 ACL denied
    複製代碼

    HA 這邊的設定

    設定 → 裝置與服務 → 新增整合 → MQTT


    • Broker:192.168.1.20
    • Port:1883
    • Username / Password:剛剛建立的


    進階設定(點「設定」):


    • Discovery prefixhomeassistant(預設,不要改)
    • Birth message / Will message:保持預設


    Birth message 的作用:HA 上線時發一則訊息,
    讓其他服務(例如 Z2M)知道要重新發送 discovery。

    沒有它的話,HA 重啟後某些裝置會消失,要等它們下次回報才回來。



    要不要加 TLS?

    純內網的話,我覺得可以不用,理由:


    • 內網流量本來就不太可能被竊聽(除非已經被入侵)
    • TLS 增加設定複雜度和憑證維護負擔
    • 有些老舊的 ESP 裝置對 TLS 支援不好


    但這些情況要加


    • MQTT 需要跨網段(例如 IoT VLAN 到主網段)
    • 有不信任的裝置在同一個網段
    • 要從外部存取(但更好的做法是走 VPN


    加 TLS 的設定
    1. listener 8883
    2. protocol mqtt
    3. cafile /mosquitto/config/certs/ca.crt
    4. certfile /mosquitto/config/certs/server.crt
    5. keyfile /mosquitto/config/certs/server.key
    6. require_certificate false
    7. tls_version tlsv1.2
    複製代碼

    自簽憑證的話客戶端要信任那個 CA
    ESP 裝置要把 CA 憑證燒進韌體 —— 這就是複雜的地方。

    除錯:一定要會的三個指令
    1. # 看所有流量(最有用)
    2. mosquitto_sub -h 192.168.1.20 -u homeassistant -P 密碼 -t '#' -v
    3. # 只看某個服務
    4. mosquitto_sub -h 192.168.1.20 -u homeassistant -P 密碼 -t 'zigbee2mqtt/#' -v
    5. # 手動發一則訊息測試
    6. mosquitto_pub -h 192.168.1.20 -u homeassistant -P 密碼 \
    7.   -t 'test/hello' -m 'world'
    複製代碼

    圖形介面的話用 MQTT Explorer(Windows / Mac / Linux 都有),
    可以樹狀瀏覽整個 broker,找問題快很多。

    HA 裡也能監聽
    設定 → 裝置與服務 → MQTT → 設定 → 監聽主題

    常見問題

    問題一:連不上,日誌說 Connection Refused: not authorised


    • 帳號密碼錯
    • passwd 檔案權限不對(要 0700 或容器使用者可讀)
    • mosquitto.conf 裡的 password_file 路徑錯


    問題二:連得上但收不到訊息


    • ACL 擋住了(看日誌會有 ACL denied)
    • 主題名稱打錯(大小寫有差)


    問題三:裝置重啟後狀態不見


    • Discovery 訊息沒有 retain
    • persistence 沒開


    問題四:訊息重複或延遲


    • 兩個服務用同一個 client_id(它們會互踢)
    • 每個客戶端的 client_id 一定要唯一


    這個症狀很有特色:兩個服務輪流斷線重連,日誌一直刷。

    維運建議


    • 日誌要輪替,不然會長很大
    • 定期備份 passwd 和 acl 檔
    • 監控 broker 活著沒有

    1. command_line:
    2.   - binary_sensor:
    3.       name: MQTT Broker
    4.       unique_id: mqtt_alive
    5.       command: >
    6.         timeout 5 mosquitto_pub -h 192.168.1.20 -p 1883
    7.         -u monitor -P 密碼 -t 'healthcheck' -m 'ping'
    8.         && echo ON || echo OFF
    9.       payload_on: "ON"
    10.       payload_off: "OFF"
    11.       scan_interval: 120
    12.       device_class: connectivity
    複製代碼

    最後一個架構建議

    前面提過,再強調一次:

    如果 MQTT 掛掉,你的 Zigbee 裝置在 HA 裡全部會變成不可用。

    所以:


    • MQTT broker 最好跟 HA 放同一台機器(同生共死,不會有一邊掛掉的問題)
    • 放 NAS 的話,要接受「NAS 重開 = 智能家居停擺」
    • 或者跑兩個 broker 做橋接(複雜,一般家庭不需要)


    我自己最後是把 MQTT 搬回 HA 主機
    NAS 只留 Frigate、InfluxDB、Grafana 這些「掛了也不影響即時控制」的服務。

    ---

    安全這件事的原則是:假設某一層一定會被突破,所以每一層都要有防護。

    MQTT 的 ACL 就是這個思路 —— 就算某個裝置被入侵,
    它也只能碰自己的那一小塊。
    您需要登入後纔可以回帖 登入 | 立即註冊

    本版積分規則

    Archiver|手機版|惟家的智能論壇

    GMT+8, 2026-9-24 11:25 , Processed in 0.073729 second(s), 24 queries .

    快速回覆 返回頂部 返回列表