說在前面html
數據在網絡上傳輸,若是是明文傳輸,確定是不安全的,因此得將數據進行加密。如今主流的加密方式,就是利用SSL/TLS協議加密,其實SSL和TLS能夠看作是一個協議,它運行在傳輸層和應用層之間的一層協議,經過將TCP/UDP傳輸的數據加密以後,再傳送到另外一端。這樣數據就安全了。node
如今的https傳輸,底層就是利用了SSL/TLS協議進行了加密。固然,Mail,FTP等其餘基於TCP/UDP傳輸協議之上構建的應用程序,也都是可使用這種加密協議的。那麼MQTT在數據傳輸中,是否也能夠進行傳輸加密呢?答案是確定的,由於MQTT也是基於TCP協議之上實現的,因此想要實現起來,並不難。git
在開始進行MQTT數據傳輸加密的實操以前,咱們先來儲備點SSL/TLS協議的知識,以便於更好的進行理解。github
說道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,描述以下:session
第一步,愛麗絲給出協議版本號、一個客戶端生成的隨機數(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頒發的證書都有時效性,物聯網設備特別多的狀況下,這種狀況顯得尤其明顯,因此針對本身的設備規模,選擇合適的認證,也是很是重要的。
本節就到這裏,但願能拋磚引玉。
參考資料: