由於MQTT運行於TCP層之上並以明文方式傳輸,這就相當於HTTP的明文傳輸,使用Wireshark可以完全看到MQTT發送的所有消息,消息指令一覽無遺,如圖1所示。
這樣可能會產生以下風險:
- 設備可能會被盜用;
- 客戶端和服務端的靜態數據可能是可訪問的(可能會被修改);
- 協議行為可能有副作用(如計時器攻擊);
- 拒絕服務攻擊;
- 通信可能會被攔截、修改、重定向或者洩露;
- 虛假控制報文注入。
作為傳輸協議,MQTT僅關注消息傳輸,提供合適的安全功能是開發者的責任。安全功能可以從三個層次來考慮——應用層、傳輸層、網絡層。
- 應用層:在應用層上,MQTT提供了客戶標識(Client Identifier)以及用戶名和密碼,可以在應用層驗證設備。
- 傳輸層:類似於HTTPS,MQTT基於TCP連接,也可以加上一層TLS,傳輸層使用TLS加密是確保安全的一個好手段,可以防止中間人攻擊。客戶端證書不但可以作為設備的身份憑證,還可以用來驗證設備。
- 網絡層:如果有條件的話,可以通過拉專線或者使用VPN來連接設備與MQTT代理,以提高網絡傳輸的安全性。
認證
MQTT支持兩種層次的認證:
- 應用層:MQTT支持客戶標識、用戶名和密碼認證;
- 傳輸層:傳輸層可以使用TLS,除了加密通訊,還可以使用X509證書來認證設備。
客戶標識
MQTT客戶端可以發送最多65535個字符作為客戶標識(Client Identifier),一般來說可以使用嵌入式芯片的MAC地址或者芯片序列號。雖然使用客戶標識來認證可能不可靠,但是在某些封閉環境或許已經足夠了。
用戶名和密碼
MQTT協議支持通過CONNECT消息的username和password字段發送用戶名和密碼。
用戶名及密碼的認證使用起來非常方便,不過由於它們是以明文形式傳輸,所以使用抓包工具就可以輕易的獲取。
一般來說,使用客戶標識、用戶名和密碼已經足夠了,比如支持MQTT協議連接的OneNET雲平臺,就是使用了這三個字段作為認證。如果感覺還不夠安全,還可以在傳輸層進行認證。
在傳輸層認證
在傳輸層認證是這樣的:MQTT代理在TLS握手成功之後可以繼續發送客戶端的X509證書來認證設備,如果設備不合法便可以中斷連接。使用X509認證的好處是,在傳輸層就可以驗證設備的合法性,在發送CONNECT消息之前便可以阻隔非法設備的連接,以節省後續不必要的資源浪費。而且,MQTT協議運行在使用TLS時,除了提供身份認證,還可以確保消息的完整性和保密性。
選擇用戶數據格式
MQTT協議只實現了傳送消息的格式,並沒有限制用戶協議需要按照一定的風格,因此在MQTT協議之上,我們需要定義一套自己的通信協議。比如說,發佈者向設備發佈一條打開消息,設備可以回覆一個消息並攜帶返回碼,這樣的消息格式是使用二進制、字符串還是JSON格式呢?下面就簡單做個選型參考。
十六進制/二進制
MQTT原本就是基於二進制實現的,所以用戶協議使用二進制實現是一個不錯的選擇。雖然失去了直觀的可讀性,但可以將流量控制在非常小。其實對於單片機開發者來說十六進制並不陌生,因為單片機寄存器都是以位來操作的,芯片間通信也會使用十六進制/二進制。而對於沒有單片機開發經驗的工程師來說,十六進制/二進制可能就太原始了。下面我們繼續看看還有沒有其他方案。
字符串
對單片機開發者來說,字符串也是一個選擇。比如通過串口傳輸的AT指令就是基於字符串通信的。使用字符串方便了人閱讀,但是對高級語言開發者來說,字符串依舊不是最佳選擇,恐怕鍵值對(Key-Value)才是最優形式。
閱讀更多 航天智造 的文章