一、概述:
物聯(lián)網(wǎng)的核心是連接萬物,通過交換并分析數(shù)據(jù)使得生活更舒適與便捷。不過,敏感數(shù)據(jù)泄露或者設(shè)備被非法控制可不是鬧著玩的。比如前段時間國內(nèi)某著名家電企業(yè)的智能洗衣機(jī),使用了某著名電商基于XMPP協(xié)議的物聯(lián)網(wǎng)平臺,不費吹灰之力便被黑客攻破并遠(yuǎn)程遙控,給智能家居的發(fā)展帶來了一些陰影。究其本質(zhì),并不是物聯(lián)網(wǎng)技術(shù)本身有缺陷,而是在物聯(lián)網(wǎng)系統(tǒng)的設(shè)計中最基本的安全設(shè)計被工程師輕視了,才導(dǎo)致整個系統(tǒng)的崩塌。
在這里我們將介紹為何以及如何運用MQTT提供的安全特性來保證物聯(lián)網(wǎng)項目的順利實施。
安全對于幾乎所有的項目都是一個挑戰(zhàn),對于物聯(lián)網(wǎng)項目更是如此:
對于以上挑戰(zhàn),MQTT提供了多個層次的安全特性:
雖然MQTT提供了多重安全設(shè)計,不過世界上并沒有銀彈能夠保障數(shù)據(jù)的絕對安全,所以應(yīng)該在設(shè)計的時候就把安全放在設(shè)計目標(biāo)之中并擁有相當(dāng)?shù)膬?yōu)先級,否則上文提到的智能洗衣機(jī)就是一個活生生的教訓(xùn)。
而網(wǎng)絡(luò)層可以使用專線或者VPN超出了本文的范圍,下面我們結(jié)合Mosquitto仔細(xì)了解一下傳輸層和應(yīng)用層的MQTT安全特性。
MQTT是基于TCP的,默認(rèn)情況通訊并不加密。如果你需要傳輸敏感信息或者對設(shè)備進(jìn)行反控,使用TSL幾乎是必須的。打個比方,如果你在咖啡店用免費Wi-Fi上網(wǎng),登錄互聯(lián)網(wǎng)金融的網(wǎng)站不支持HTTPS傳輸,那么你的賬號信息多半已經(jīng)在咖啡店的Wi-Fi日志里面躺著了……
TSL是非常成熟的安全協(xié)議,在握手的時候便可以創(chuàng)建安全連接,使得黑客無法偷聽或者篡改內(nèi)容了。使用TLS的時候有以下注意點:
當(dāng)然,TLS會增加連接時開銷,對低運算能力的設(shè)備而言是額外的負(fù)擔(dān),不過如果設(shè)備是長連接的話就會避免反復(fù)連接的開銷。
Mosquitto原生支持了TLS加密,生成證書后再配置一下MQTT代理即可。
首先我們需要生成證書權(quán)威(Certificate Authority,CA)的認(rèn)證和密鑰,生成過程中Common Name一定要填寫Fully Qualified Domain Name(測試期間用IP地址也湊合):
openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
接下來生成MQTT代理使用的密鑰:
openssl genrsa -des3 -out server.key 2048
并去除密碼:
openssl genrsa -out server.key 2048
然后為MQTT代理準(zhǔn)備一個認(rèn)證注冊請求(Certificate Signing Request,CSR),這里的Common Name也要寫對:
openssl req -out server.csr -key server.key -new
最后通過CA簽署這個CSR生成MQTT代理證書:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
現(xiàn)在配置/etc/mosquitto/mosquitto.conf,確保8883端口的設(shè)置如下:
listener 8883cafile /etc/mosquitto/tls/ca.crtcertfile /etc/mosquitto/tls/server.crtkeyfile /etc/mosquitto/tls/server.key
重啟Mosquitto服務(wù)就可以用以下命令訂閱和發(fā)布消息了,當(dāng)然所有消息都由TLS加密,可以無憂無慮地傳遞私密信息啦:
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crtmosquitto_pub -h host -p 8883 -t 'topic' -m '15' --cafile ca.crt
其中,host需要與前面指定的Common Name一致,否則TLS連接會報錯,錯誤信息也不是很直觀……
認(rèn)證是驗證設(shè)備身份的過程。拿旅行做比方,在換登機(jī)牌的時候需要出示護(hù)照以驗明正身,即使別人能夠假冒你的名字,但是拿不出護(hù)照便無法偽造身份。買房的時候,需要通過戶口本證明你媽是你媽。
MQTT支持兩種層次的認(rèn)證:
通過傳輸層和應(yīng)用層來解釋認(rèn)證并不直觀,下面我們直接從客戶標(biāo)識、用戶名密碼以及X509證書的角度來了解認(rèn)證。
用戶可以使用最多65535個字符作為客戶標(biāo)識(Client Identifier),UUID或者M(jìn)AC地址最為常見。
使用客戶標(biāo)識來認(rèn)證并不可靠,不過在某些封閉的環(huán)境中或許已經(jīng)足夠。
MQTT協(xié)議支持通過CONNECT消息的username和password字段發(fā)送用戶名和密碼。
用戶名密碼的認(rèn)證使用起來非常方便,不過再強調(diào)一下,由于用戶名密碼是以明文形式傳輸,在通過互聯(lián)網(wǎng)時使用TSL加密是必須的。
Mosquitto支持用戶名/密碼認(rèn)證方式,只要確保/etc/mosquitto/mosquitto.conf有如下設(shè)置:
password_file /etc/mosquitto/passwdallow_anonymous false
其中passwd文件是用來保存用戶名和密碼的,可以通過mosquitto_passwd來維護(hù)用戶名密碼。之后便可以通過如下命令訂閱和發(fā)布消息了:
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt -u user -P pwdmosquitto_pub -h host -p 8883 -t 'topic' -m '9' --cafile ca.crt -u user -P pwd
這里端口使用8883是假設(shè)已經(jīng)配置了TLS加密的。
結(jié)合TLS加密的用戶名密碼認(rèn)證,已經(jīng)是相對完善的安全體系了。
MQTT代理在TLS握手成功之后可以繼續(xù)發(fā)送客戶端的X509證書來認(rèn)證設(shè)備,如果設(shè)備不合法便可以中斷連接。
使用X509認(rèn)證的好處,是在傳輸層就可以驗證設(shè)備的合法性,在發(fā)送MQTT CONNECT之前便可以阻隔非法設(shè)備的連接,以節(jié)省后續(xù)不必要的資源浪費。
如果你可以控制設(shè)備的創(chuàng)建和設(shè)置,X509證書認(rèn)證或許是個非常好的選擇。不過代價也是有的:
MQTT原生支持X509認(rèn)證,生成客戶證書后再配置一下MQTT代理便可。
首先生成設(shè)備密鑰:
openssl genrsa -des3 -out client.key 2048
然后為準(zhǔn)備一個設(shè)備認(rèn)證注冊請求:
openssl req -out client.csr -key client.key -new
最后通過CA簽署這個CSR生成設(shè)備證書:
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
現(xiàn)在配置/etc/mosquitto/mosquitto.conf,確保8883端口的設(shè)置如下:
listener 8883cafile /etc/mosquitto/tls/ca.crtcertfile /etc/mosquitto/tls/server.crtkeyfile /etc/mosquitto/tls/server.keyrequire_certificate true
重啟Mosquitto服務(wù)就可以用以下命令訂閱和發(fā)布消息了,當(dāng)然所有消息都由TLS加密,可以無憂無慮地傳遞私密信息啦:
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt --cert client.crt --key client.keymosquitto_pub -h host -p 8883 -t 'topic' -m '95' --cafile ca.crt --cert client.crt --key client.key
可以看到,X509同時提供了完善的加密和驗證,只是證書的生命周期管理的代價要比用戶名密碼高一些。
授權(quán)是對資源的訪問權(quán)限。繼續(xù)拿機(jī)場做例子,在使用護(hù)照認(rèn)證了用戶之后,系統(tǒng)會根據(jù)預(yù)定決定用戶可以上特定時間和班次的飛機(jī),這就是授權(quán)。
對MQTT而言意味著對主題的訂閱和發(fā)布權(quán)限。Mosquitto內(nèi)置了基本的授權(quán),那就是基于Access Control List的授權(quán)。
由于ACL是基于特定用戶的,所以需要使用用戶名密碼認(rèn)證方式。然后,在/etc/mosquitto/mosquitto.conf中指定ACL文件:
acl_file /etc/mosquitto/acl
在這個ACL文件便可以指定用戶的讀寫權(quán)限,比如下面便可以授權(quán)用戶tom讀寫指定主題的權(quán)限:
user tomtopic readwrite company/building/floor/#
Mosquitto只提供了基本的基于ACL的授權(quán),更高級的基于RBAC的授權(quán)可能需要通過插件的形式自行開發(fā)了。
在MQTT項目實施時,還可以考慮通過防火墻保護(hù)MQTT代理: