說在前面
數據在網絡上傳輸,如果是明文傳輸,肯定是不安全的,所以得將數據進行加密。現在主流的加密方式,就是利用SSL/TLS協議加密,其實SSL和TLS可以看做是一個協議,它運行在傳輸層和應用層之間的一層協議,通過將TCP/UDP傳輸的數據加密之後,再傳送到另一端。這樣數據就安全了。
現在的https傳輸,底層就是利用了SSL/TLS協議進行了加密。當然,Mail,FTP等其他基於TCP/UDP傳輸協議之上構建的應用程序,也都是可以使用這種加密協議的。那麼MQTT在數據傳輸中,是否也可以進行傳輸加密呢?答案是肯定的,因爲MQTT也是基於TCP協議之上實現的,所以想要實現起來,並不難。
在開始進行MQTT數據傳輸加密的實操之前,我們先來儲備點SSL/TLS協議的知識,以便於更好的進行理解。
說道SSL/TLS協議,其誕生可以追溯到前瀏覽器霸主NetScape,爲了解決數據傳輸安全問題而發明了SSL協議,先是產生了SSL1.0,然後產生了SSL2.0,之後是SSL3.0,由於協議成熟且使用量大,後來被IETF對SSL3.0進行了標準化並添加了少量其他機制,更名成了TLS1.0。更多的細節,可以百度“RFC2246-TLS加密協議詳解”,也可以去www.rfc-editor.org網站,通過搜索RFC2246來了解更多細節。
OPENSSL,是對SSL/TLS協議進行實現的開源軟件,其中包含了加解密所用到的各種算法,算是密碼學這塊的集大成者。
今天我們要用它來通過特定的流程來生產出我們需要的加密機制,從而使得MQTT的傳輸更安全。
握手流程
首先來說明一下SSL/TLS協議的經典握手流程,只有通過此流程,後續的數據傳輸才能正常的進行加密並傳輸。整體流程如下:
由於上圖描述都是英文,理解起來比較困難,我就拿阮一峯的描述來進行,Vistor我們稱爲Alice,CloudFlare我們稱爲Bob,描述如下:
第一步,愛麗絲給出協議版本號、一個客戶端生成的隨機數(Client random),以及客戶端支持的加密方法。
第二步,鮑勃確認雙方使用的加密方法,並給出數字證書、以及一個服務器生成的隨機數(Server random)。
第三步,愛麗絲確認數字證書有效,然後生成一個新的隨機數(Premaster secret),並使用數字證書中的公鑰,加密這個隨機數,發給鮑勃。
第四步,鮑勃使用自己的私鑰,獲取愛麗絲髮來的隨機數(即Premaster secret)。
第五步,愛麗絲和鮑勃根據約定的加密方法,使用前面的三個隨機數,生成"對話密鑰"(session key),用來加密接下來的整個對話過程。
可以看到整體流程比較複雜,而且涉及到了加密方法,數字證書,公鑰,私鑰等名詞,我大概做一下解釋。
加密方法:數據傳輸加密,可以用多種方法,圖例中選用的是RSA,即非對稱加密算法。
公鑰:公開的密匙文件,任何用戶都可以自由訪問,通常以.pem結尾
私鑰:非公開的密匙文件,通常由加密方自己保管,必須得保證其私密性,通常以.key結尾
數字證書:包含數字簽名和公鑰的證書,客戶端可以通過CA來驗證數字簽名,通常以.cer, .crt結尾
大致知道這些名詞的意思後,接下來我們通過更加具體的流程講解,來逐漸清晰化。
授權流程
CA中心的授權流程
由於CA證書要進行證書授權,所以必須先創建一個自己的私鑰,然後通過此私鑰生成自己的自簽證書。由於這裏我們無法真正的CA中心來模擬,因爲是收費的,好在openssl爲我們提供了自建CA中心的選項,使得可以使用如下的命令來模擬。
1.創建私鑰,執行命令:
openssl genrsa -out D:/sslkey/ca/MyRootCA.key 2048
可以看到在文件夾中生成了私鑰
2.生成自簽證書,執行命令:
openssl req -x509 -new -nodes -key D:/sslkey/ca/MyRootCA.key -sha256 -days 3650 -subj "/CN=www.scy.com" -out D:/sslkey/ca/MyRootCA.pem
填寫好相關信息後,最終在文件夾中生成了自簽證書。需要說明的是,由於是模擬的CA中心,所以這裏稍顯繁瑣,如果使用的是外部CA中心,則無需關心這些問題。同時,如果用戶想自定義自己的信息,請把-subj配置去掉即可,後面的請求也類似。
CA證書整體的準備工作到此。
Server端的授權流程
Server端的授權流程也比較簡單,首先是創建server端使用的私鑰,然後通過此私鑰創建證書請求,請求會被推送到CA中心進行處理,處理完畢後,會將證書頒發給Server端。
1.創建私鑰,執行命令:
openssl genrsa -out D:/sslkey/server/MyEMQ1.key 2048
2.創建證書請求,執行命令:
openssl req -new -key D:/sslkey/server/MyEMQ1.key -out D:/sslkey/server/MyEMQ1.csr -subj "/CN=127.0.0.1"
3.CA中心頒發證書,執行命令:
openssl x509 -req -in D:/sslkey/server/MyEMQ1.csr -CA D:/sslkey/ca/MyRootCA.pem -CAkey D:/sslkey/ca/MyRootCA.key -CAcreateserial -out D:/sslkey/server/MyEMQ1.pem -days 3650 -sha256
執行這三步完畢之後,整體流程完畢,我們接下來將這些文件配置到EMQ的配置文件中來啓動SSL。
打開etc目錄中的emqx.conf文件,修改選項爲以下三個配置(需要提前將授權文件拷貝到certs目錄):
#ssl port:
listener.ssl.external = 8883
#private key for emq cert:
listener.ssl.external.keyfile = etc/certs/MyEMQ1.key
#emq cert:
listener.ssl.external.certfile = etc/certs/MyEMQ1.pem
#CA cert:
listener.ssl.external.cacertfile = etc/certs/MyRootCA.pem
之後,重啓EMQX服務器即可。
這樣,此根證書生成完畢,然後就能爲後續進來的請求進行授權操作。
接下來打開MQTTX客戶端程序,建立SSL鏈接來試試是否可以正常操作:
配置好之後,點擊連接按鈕,進行連接,可以看到已經連接到服務器且在在ssl端口8883進行監聽了。
然後嘗試向/test/say管道發送消息,可以看到訂閱者已經能接收到了:
發佈者界面如下:
訂閱者界面如下:
雙向認證流程
上面配置好Server端的授權流程後,我們成功的使用客戶端通過SSL連接上了服務端並進行了消息操控。但是上面只是單向認證流程,因爲Client端並未做認證操作。這裏我們將來說下怎麼進行雙向認證流程。
Server端的授權流程,我就不用說了,上面有講解到。按照流程操作即可。
Client端的授權流程,其實和Server端的授權流程一模一樣,我們來依葫蘆畫瓢一下,進入C:\Program Files\OpenSSL-Win64\bin目錄,執行下面的命令。
1.創建私鑰,執行命令:
openssl genrsa -out D:/sslkey/client/MyClient1.key 2048
2.創建證書請求,執行命令:
openssl req -new -key D:/sslkey/client/MyClient1.key -out D:/sslkey/client/MyClient1.csr -subj "/CN=127.0.0.1"
3.CA中心頒發證書,執行命令:
openssl x509 -req -in D:/sslkey/client/MyClient1.csr -CA D:/sslkey/ca/MyRootCA.pem -CAkey D:/sslkey/ca/MyRootCA.key -CAcreateserial -out D:/sslkey/client/MyClient1.pem -days 3650 -sha256
全部執行完畢,則Client端的授權流程完畢,結果如下:
文件生成如下:
之後,我們需要配置一下,以便於啓動EMQ的客戶端SSL認證,同樣的打開etc目錄中的emqx.conf文件,修改如下配置:
#enable the client side certificates
listener.ssl.external.verify = verify_peer
#set it to 'true' to allow the ssl with client side certificate only
listener.ssl.external.fail_if_no_peer_cert = true
然後重新啓動EMQX即可。
上圖爲配置方式,配置完畢之後,點擊連接按鈕,就可以連接到Server了。之後模擬信息收發:
題外話
單向認證和雙向認證,少了一個認證步驟,一般在物聯網Client設備較多的情況下,使用單向認證則可以獲得更好的性能。如果數據非常重要且不會有性能問題的時候,使用雙向設備則更合適。
考慮到CA頒發的證書都有時效性,物聯網設備特別多的情況下,這種情況顯得尤爲明顯,所以針對自己的設備規模,選擇合適的認證,也是非常重要的。
本節就到這裏,希望能拋磚引玉。
參考資料: