MQTT安全篇


物聯網的核心是連接萬物,通過交換並分析數據使得生活更舒適與便捷。不過,敏感數據泄露或者設備被非法控制可不是鬧着玩的。比如前段時間國內某著名家電企業的智能洗衣機,使用了某著名電商基於XMPP協議的物聯網平台,不費吹灰之力便被黑客攻破並遠程遙控,給智能家居的發展帶來了一些陰影。究其本質,並不是物聯網技術本身有缺陷,而是在物聯網系統的設計中最基本的安全設計被工程師輕視了,才導致整個系統的崩塌。
在這里我們將介紹為何以及如何運用MQTT提供的安全特性來保證物聯網項目的順利實施。
安全對於幾乎所有的項目都是一個挑戰,對於物聯網項目更是如此:
  • 設備安全性與設備可用性之間往往是零和博弈。
  • 加密算法需要更多的計算能力,而物聯網設備的性能往往非常有限。
  • 物聯網的網絡條件常常要比家庭或者辦公室的網絡條件差許多。
對於以上挑戰,MQTT提供了多個層次的安全特性:
  1. 網絡層:有條件可以通過拉專線或者使用VPN來連接設備與MQTT代理,以提高網絡傳輸的安全性。
  2. 傳輸層:傳輸層使用TLS加密是確保安全的一個好手段,可以防止中間人攻擊(Man-In-The-Middle Attack)。客戶端證書不但可以作為設備的身份憑證,還可以用來驗證設備。
  3. 應用層:MQTT還提供客戶標識(Client Identifier)以及用戶名密碼,在應用層驗證設備。
雖然MQTT提供了多重安全設計,不過世界上並沒有銀彈能夠保障數據的絕對安全,所以應該在設計的時候就把安全放在設計目標之中並擁有相當的優先級,否則上文提到的智能洗衣機就是一個活生生的教訓。
網絡層可以使用專線或者VPN超出了本文的范圍,下面我們結合Mosquitto仔細了解一下傳輸層和應用層的MQTT安全特性。
加密
MQTT是基於TCP的,默認情況通訊並不加密。如果你需要傳輸敏感信息或者對設備進行反控,使用TLS幾乎是必須的。打個比方,如果你在咖啡店用免費Wi-Fi上網,登錄互聯網金融的網站不支持HTTPS傳輸,那么你的賬號信息多半已經在咖啡店的Wi-Fi日志里面躺着了……
TLS是非常成熟的安全協議,在握手的時候便可以創建安全連接,使得黑客無法竊聽或者篡改內容了。使用TLS的時候有以下注意點:
  • 盡可能使用高版本的TLS。
  • 驗證X509證書鏈防止中間人攻擊。
  • 盡量使用有CA發布的證書。
當然,TLS會增加連接時開銷,對低運算能力的設備而言是額外的負擔,不過如果設備是長連接的話就會避免反復連接的開銷。
Mosquitto原生支持了TLS加密,生成證書后再配置一下MQTT代理即可。
首先我們需要生成證書權威(Certificate Authority,CA)的認證和密鑰,生成過程中Common Name一定要填寫Fully Qualified Domain Name(測試起見用IP地址也湊合):
1
openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
接下來生成MQTT代理使用的密鑰:
1
openssl genrsa -des3 -out server.key 2048
並去除密碼:
1
openssl genrsa -out server.key 2048
然后為MQTT代理准備一個認證注冊請求(Certificate Signing Request,CSR),這里的Common Name也要寫對:
1
openssl req -out server.csr -key server.key -new
最后通過CA簽署這個CSR生成MQTT代理證書:
1
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
現在配置/etc/mosquitto/mosquitto.conf,確保8883端口的設置如下:
1
2
3
4
listener 8883
cafile /etc/mosquitto/tls/ca.crt
certfile /etc/mosquitto/tls/server.crt
keyfile /etc/mosquitto/tls/server.key
重啟Mosquitto服務就可以用以下命令訂閱和發布消息了,當然所有消息都由TLS加密,可以無憂無慮地傳遞私密信息啦:
1
2
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt
mosquitto_pub -h host -p 8883 -t 'topic' -m '15' --cafile ca.crt
其中,host需要與前面指定的Common Name一致,否則TLS連接會報錯,錯誤信息也不是很直觀……
認證
認證是驗證設備身份的過程。拿旅行做比方,在換登機牌的時候需要出示護照以驗明正身,即使別人能夠假冒你的名字,但是拿不出護照便無法偽造身份。買房的時候,需要通過戶口本證明你媽是你媽。
MQTT支持兩種層次的認證:
  • 傳輸層:傳輸層使用TLS不但可以加密通訊,還可以使用X509證書來認證設備。
  • 應用層:MQTT支持客戶標識、用戶名密碼以及X509證書,在應用層驗證設備。
通過傳輸層和應用層來解釋認證並不直觀,下面我們直接從客戶標識、用戶名密碼以及X509證書的角度來了解認證。
客戶標識
用戶可以使用最多65535個字符作為客戶標識(Client Identifier),UUID或者MAC地址最為常見。
使用客戶標識來認證並不可靠,不過在某些封閉的環境中或許已經足夠。
用戶名密碼
MQTT協議支持通過CONNECT消息的username和password字段發送用戶名和密碼。
用戶名密碼的認證使用起來非常方便,不過再強調一下,由於用戶名密碼是以明文形式傳輸,在通過互聯網時使用TSL加密是必須的。
Mosquitto支持用戶名/密碼認證方式,只要確保/etc/mosquitto/mosquitto.conf有如下設置:
1
2
password_file /etc/mosquitto/passwd
allow_anonymous false
其中passwd文件是用來保存用戶名和密碼的,可以通過mosquitto_passwd來維護用戶名密碼。之后便可以通過如下命令訂閱和發布消息了:
1
2
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt -u user -P pwd
mosquitto_pub -h host -p 8883 -t 'topic' -m '9' --cafile ca.crt -u user -P pwd
這里端口使用8883是假設已經配置了TLS加密的。
結合TLS加密的用戶名密碼認證,已經是相對完善的安全體系了。
X509證書
MQTT代理在TLS握手成功之后可以繼續發送客戶端的X509證書來認證設備,如果設備不合法便可以中斷連接。
使用X509認證的好處,是在傳輸層就可以驗證設備的合法性,在發送MQTT CONNECT之前便可以阻隔非法設備的連接,以節省后續不必要的資源浪費。
如果你可以控制設備的創建和設置,X509證書認證或許是個非常好的選擇。不過代價也是有的:
  1. 需要設計證書創建流程。如果你對設備有着完全的控制,在設備出廠前就能燒錄X509證書到設備中,那么這條路是非常合適的。但是,對於移動設備等無法實現燒錄證書的場景,用戶名/密碼認證或許是更好的選擇。
  2. 需要管理證書的生命周期,最好通過PKI(Public-Key-Infrastructure)來管理。
  3. 如果證書泄露了,一定要立即使證書失效。一個選擇是使用證書黑名單(Certificate Revocation Lists),另一個選擇是提供在線證書狀態協議(Online Certificate Status Protocol),方便MQTT代理及時了解證書的狀態。
MQTT原生支持X509認證,生成客戶證書后再配置一下MQTT代理便可。
首先生成設備密鑰:
1
openssl genrsa -des3 -out client.key 2048
然后為准備一個設備認證注冊請求:
1
openssl req -out client.csr -key client.key -new
最后通過CA簽署這個CSR生成設備證書:
1
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
現在配置/etc/mosquitto/mosquitto.conf,確保8883端口的設置如下:
1
2
3
4
5
listener 8883
cafile /etc/mosquitto/tls/ca.crt
certfile /etc/mosquitto/tls/server.crt
keyfile /etc/mosquitto/tls/server.key
require_certificate true
重啟Mosquitto服務就可以用以下命令訂閱和發布消息了,當然所有消息都由TLS加密,可以無憂無慮地傳遞私密信息啦:
1
2
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt --cert client.crt --key client.key
mosquitto_pub -h host -p 8883 -t 'topic' -m '95' --cafile ca.crt --cert client.crt --key client.key
可以看到,X509同時提供了完善的加密和驗證,只是證書的生命周期管理的代價要比用戶名密碼高一些。
授權
授權是對資源的訪問權限。繼續拿機場做例子,在使用護照認證了用戶之后,系統會根據預定決定用戶可以上特定時間和班次的飛機,這就是授權。
對MQTT而言意味着對主題的訂閱和發布權限。Mosquitto內置了基本的授權,那就是基於Access Control List的授權。
由於ACL是基於特定用戶的,所以需要使用用戶名密碼認證方式。然后,在/etc/mosquitto/mosquitto.conf中指定ACL文件:
1
acl_file /etc/mosquitto/acl
在這個ACL文件便可以指定用戶的讀寫權限,比如下面便可以授權用戶tom讀寫指定主題的權限:
1
2
user tom
topic readwrite company/building/floor/#
Mosquitto只提供了基本的基於ACL的授權,更高級的基於RBAC的授權可能需要通過插件的形式自行開發了。
體系
在MQTT項目實施時,還可以考慮通過防火牆保護MQTT代理:
  • 僅允許相關的流量傳遞到MQTT代理,比如UDP、ICMP等流量可以直接屏蔽掉。
  • 僅允許相關端口的流量傳遞到MQTT代理,比如MQTT over TCP使用1883,而MQTT over TLS使用8883。
  • 僅允許某些IP地址段來訪問MQTT代理,如果業務場景允許的話。
篇幅有限,本文只涉及了MQTT安全體系設計的冰山一角,如果讀者感興趣還可以參考HiveMQ發布的 Introducing the MQTT Security Fundamentals系列博文。堡壘往往最容易從內部攻破,只有在系統在設計的時候就把安全放在首要位置並且積極地去做威脅模型分析,這才能有效保護用戶數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM