用TLS/SSL保證EMQ的網絡傳輸安全


作為基於現代密碼學公鑰算法的安全協議,TLS/SSL能在計算機通訊網絡上保證傳輸安全,EMQ的MQTT broker支持TLS,也可以用這種方式來確保傳輸安全。

參考官網:https://www.emqx.io/cn/blog/emqx-server-ssl-tls-secure-connection-configuration-guide

TLS/SSL帶來的安全優勢

  • 強認證。 用TLS建立連接的時候,通訊雙方可以互相檢查對方的身份。在實踐中,很常見的一種身份檢查方式是檢查對方持有的X.509數字證書。這樣的數字證書通常是由一個受信機構辦法的,不可偽造。
  • 保證機密性 TLS通訊的每次會話都會由會話密鑰加密,會話密鑰有通訊雙方協商產生。任何第三方都無法知曉通訊內容。即使一次會話的密鑰泄露,並不影響其他會話的安全性。
  • 完整性。 加密通訊中的數據很難被篡改而不被發現。

接下來EMQ君將介紹TLS/SSL協議以及如何在EMQ上啟用。

TLS/SSL協議

TLS/SSL協議下的通訊過程分為兩部分,第一部分是握手協議。握手協議的目的是鑒別對方身份並建立一個安全的通訊通道。握手完成之后雙方會協商出接下來使用的密碼套件和會話密鑰;第二部分是record協議,redord和其他數據傳輸協議非常類似,會攜帶內容類型,版本,長度和荷載等信息,不同的是它所攜帶的信息是加密了的。

下面的圖片描述了TLS/SSL握手協議的過程,從客戶端的“hello”一直到服務器的“finished”完成握手。有興趣的同學可以放狗找更詳細的資料看。對這個過程不了解也並不影響我們在EMQ中啟用這個功能。

在EMQ中啟用TLS/SSL的准備工作

通常來說,我們會需要數字證書來保證TLS通訊的強認證。數字證書的試用本身是一個三方協議,除了通訊雙方,還有一個頒發證書的受信第三方,有時候這個受信第三方就是一個CA。和CA的通訊,一般是以預先發行證書的方式進行的。也就是在開始TLS通訊的時候,我們需要至少有2個證書,一個CA的,一個EMQ的,EMQ的證書由CA頒發,並用CA的證書驗證。如果要做雙向認證,還會用到一個客戶端證書。

獲得一個真正受外界信任的證書會有一定的開銷。在實驗室環境,我們可以用自己生成的證書來模擬這個過程。接下來的演示,EMQ君就是用的這個方法。

在這里,我們假設您的系統已經安裝了OpenSSL。試用OpenSSL附帶的工具集就可以生成我們需要的證書了。

首先,我們需要一個自簽名的CA證書。生成這個證書需要有一個私鑰為它簽名,如果還沒有合適的私鑰的話,可以在命令行上執行以下命令來生成一個:

openssl genrsa -out MyRootCA.key 2048

這個命令將生成一個密鑰長度2048的密鑰並保存在MyRootCA.key,有了這個密鑰,就可以用它來生成EMQ broker的根證書了,請求中需要填寫一些信息,盡量和下面新建的openssl.cnf文件中的信息一樣:

 openssl req -x509 -new -nodes -key MyRootCA.key -sha256 -days 3650 -out MyRootCA.pem 

根證書是整個信任鏈的起點,如果一個證書的每一級簽發者向上一直到根證書都是可信的,那個我們就可以認為這個證書也是可信的。有了這個根證書,我們就可以用它來給其他實體簽發實體證書了。

生成server端秘鑰和證書

實體(在這里就是EMQ Broker)也需要一個自己的私鑰對來保證它對自己證書的控制權。生成這個密鑰的過程和上面類似:

openssl genrsa -out MyEMQ.key 2048 

新建 openssl.cnf 文件,

  • req_distinguished_name :根據情況進行修改,
  • alt_names: BROKER_ADDRESS 修改為 EMQ X 服務器實際的 IP 或 DNS 地址,例如:IP.1 = 127.0.0.1,或 DNS.1 = broker.xxx.com
[req]
default_bits  = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
countryName = CN
stateOrProvinceName = Jiangsu
localityName = Suzhou 
organizationName = test.io
commonName = www.test.com
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
## IP.1 = BROKER_ADDRESS
DNS.1 = www.test.com

然后以這個密鑰簽發一個證書請求,請求中需要填寫一些信息,盡量和上面新建的 openssl.cnf文件中的信息一樣:
openssl req -new -key ./ MyEMQ.key -config openssl.cnf -out MyEMQ.csr
然后以根證書來簽發EMQ Broker的實體證書了:
openssl x509 -req -in ./MyEMQ.csr -CA MyRootCA.pem -CAkey MyRootCA.key -CAcreateserial -out MyEMQ.pem -days 3650 -sha256 -extensions v3_req -extfile openssl.cnf

現在,我們可以啟用EMQ的TLS/SSL連接了

在EMQ Broker上啟用TLS/SSL

啟用TLS/SSL的過程是比較簡單的,只需要修改emq.conf文件中的一些配置就可以了:

listener.ssl.external = 8883 #private key for emq cert: listener.ssl.external.keyfile = etc/certs/MyEMQ.key #emq cert: listener.ssl.external.certfile = etc/certs/MyEMQ.pem #CA cert: listener.ssl.external.cacertfile = etc/certs/MyRootCA.pem 

重啟EMQ后,用mosquittu_sub來驗證TLS是否正常啟動:

然后以根證書來簽發EMQ Broker的實體證書了:
mosquitto_sub -t abc -h 192.168.238.132 -p 8883 -d --cafile ~/test_certs/MyRootCA.pem --insecure Client mosqsub|10617-Zhengyus- sending CONNECT Client mosqsub|10617-Zhengyus- received CONNACK Client mosqsub|10617-Zhengyus- sending SUBSCRIBE (Mid: 1, Topic: abc, QoS: 0) Client mosqsub|10617-Zhengyus- received SUBACK Subscribed (mid: 1): 0 

這個結果和我們期待的一樣。moqsuitto客戶端通過TLS/ssl正常連接並訂閱主題。
如果我們從EMQ的Dashboard上看的話,可以看到在8883端口上有一個mqtt:ssl連接:

 

啟用TLS/SSL的雙向驗證

在一些對於身份驗證要求比較嚴格的場景,也會要求EMQ對客戶端的身份用證書進行驗證。這時候就需要啟動雙向驗證了。

emq.conf中啟動對對端的證書驗證:

#enable the client side certificates
listener.ssl.external.verify = verify_peer

emq.conf中強制對對端的證書驗證:

#set it to 'true' to allow the ssl with client side certificate only listener.ssl.external.fail_if_no_peer_cert = true 

完成上面的步驟后,如果我們再想用之前的方式連接EMQ,客戶端就會被拒絕:

mosquitto_sub -t abc -h emq1 -p 8883 -d --cafile ~/test_certs/MyRootCA.pem --insecure Client mosqsub|10738-Zhengyus- sending CONNECT Error: A TLS error occurred. 

生成client端秘鑰和證書

現在我們試用和生成服務器端證書一樣的方法來生成客戶端證書:

openssl genrsa -out MyClient.key 2048
openssl req -new -key ./MyClient.key -config openssl.cnf -out MyClient.csr
openssl x509 -req -in ./MyClient.csr -CA MyRootCA.pem -CAkey MyRootCA.key -CAcreateserial -out MyClient.pem -days 3650 -sha256 -extensions v3_req -extfile openssl.cnf

修改mosquitto_sub的命令行啟動客戶端證書驗證:

mosquitto_sub -t abc -h 192.168.238.132 -p 8883 -d --key ~/test_certs/MyClient.key --cert ~/test_certs/MyClient.pem --cafile ~/test_certs/MyRootCA.pem --insecure Client mosqsub|10796-Zhengyus- sending CONNECT Client mosqsub|10796-Zhengyus- received CONNACK Client mosqsub|10796-Zhengyus- sending SUBSCRIBE (Mid: 1, Topic: abc, QoS: 0) Client mosqsub|10796-Zhengyus- received SUBACK Subscribed (mid: 1): 0 

 

也可以嘗試python客戶端:

import paho.mqtt.client as mqtt
import json, os

sub_list = [("abc", 0), ('pub', 2)]

def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    # 連接成功回調
    result, mid = client.subscribe(sub_list)
    # print('result:', result)
    # print('mid:', mid)


# 接收到消息的回調方法
def on_message(client, userdata, msg):
    payload = msg.payload.decode()
    print(msg.topic)
    print(payload)
    # print(msg.topic + ":" + payload)


if __name__ == '__main__':
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    # client.username_pw_set("username", "pwd")
    crtPath = os.path.dirname(os.path.abspath(__file__)) + r"\crt"
    ca_certs = "%s\ca\MyRootCA.pem" % crtPath
    certfile = "%s\client\MyClient.pem" % crtPath
    keyfile = "%s\client\MyClient.key" % crtPath
    print(ca_certs)
    client.tls_set(ca_certs=ca_certs,
                   certfile=certfile,
                   keyfile=keyfile,
                   )
    client.tls_insecure_set(True)

   
    HOST = "192.168.238.132"

    client.connect(HOST, 8883, 30)
    # client.loop_forever()

    client.loop_start()

    while True:
        str = input()
        if str:
            client.publish("abc", str, 0)
 


 


免責聲明!

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



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