EMQ X 認證鑒權(一)——基於 MySQL 的 MQTT 連接認證


前言

安全保護幾乎對於所有的項目都是一個挑戰,對於物聯網項目更是如,自普及應用以來物聯網業內已經發生過多起安全事故。

作為物聯網通信協議事實標准,MQTT 保持着較高的安全性,提供了多層次的安全設計:

  • 傳輸層:MQTT 基於 TCP/IP 協議,可以在傳輸層上使用 SSL/TLS 進行加密傳輸:
    • 使用 SSL/TLS 加密通信數據,防止中間人攻擊;
    • 使用客戶端證書作為設備身份憑證,驗證設備合法性。
  • 應用層:使用 MQTT 自身的安全特性進行防護:
    • MQTT 協議支持用戶名和密碼實現客戶端的身份校驗;
    • MQTT Broker 實現了 Topic 的讀寫權限控制(Topic ACL)。

EMQ X 完整支持 MQTT 各項安全規范,內置的安全功能無需編程開箱即用,可以快速排除項目中的安全隱患。本系列將圍繞各個層次的安全規范,介紹如何通過配置 EMQ X 啟用相關功能最終實現相應的安全防護。

emqx-auth-mysql 簡介

emqx_auth_mysql 是基於 MySQL 數據庫的 MQTT 認證/訪問控制插件,通過檢查每個終端接入的 usernamepassword 是否與用戶指定的 MySQL 數據庫中存儲的信息一致性來實現對終端的連接認證和訪問控制。其功能邏輯如下:

本文僅介紹認證功能,ACL 功能見后續文章。

認證原理

設備連接時 EMQ X 將執行按照配置的查詢語句,比較查詢結果中的 password 字段的值是否與當前請求客戶端的密碼進行加鹽 (salt) 處理、加密后的值是否相等,驗證流程如下:

  • 查詢結果集中必須有 passwordsalt 字段,可以使用 AS 語法設置如 SELECT *, pwd as password FROM mqtt_user
  • 在數據庫中可以為每個客戶端都指定一個 salt,EMQ X 根據客戶端傳入的密碼和通過 SQL 返回的 salt 信息生成密文
  • 結果集為空或比對結果不相等,認證失敗

創建數據庫

你可以使用任何自己喜歡的 客戶端,創建好相應的數據庫。這里用的是 MySQL 自帶的命令行客戶端,打開 MySQL 的控制台,如下所示,創建一個名為 emqx 的認證數據庫,並切換到 emqx 數據庫。

mysql> create database emqx;
Query OK, 1 row affected (0.00 sec)

mysql> use emqx;
Database changed

創建表

建議的表結構如下,其中,

  • username 為客戶端連接的時候指定的用戶名
  • password_hash 為使用 salt 加密后的密文
  • salt 為加密串
  • is_superuser 是否為超級用戶,用於控制 ACL,缺省為0;設置成 1 的時候為超級用戶,可以跳過 ACL 檢查

數據表字段可以不用完全跟下面的一致,可以根據業務需要設置,通過 emqx_auth_mysql.conf 配置文件中的 auth_query 配置項來指定。

CREATE TABLE `mqtt_user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password_hash` varchar(255) DEFAULT NULL,
  `salt` varchar(40) DEFAULT NULL,
  `is_superuser` tinyint(1) DEFAULT 0,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mqtt_username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

創建成功后,查看一下表結構如下,

mysql> desc mqtt_user;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| id            | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| username      | varchar(100)     | YES  | UNI | NULL    |                |
| password_hash | varchar(255)     | YES  |     | NULL    |                |
| salt          | varchar(40)      | YES  |     | NULL    |                |
| is_superuser  | tinyint(1)       | YES  |     | 0       |                |
| created       | datetime         | YES  |     | NULL    |                |
+---------------+------------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)

准備認證數據

本文提供示例數據中密碼為 test_password,加密 salt 為 secret。即客戶端連接時使用的密碼是 test_password

在 EMQ X 的配置文件的 auth.mysql.password_hash 中,salt 只是一個標識符,表示 salt 與密碼明文的拼接關系

  • 如果采用auth.mysql.password_hash = md5,salt ,那么 EMQ X 使用 MD5 算法對 test_passwordsecret 字符串加密
  • 如果采用auth.mysql.password_hash = salt,md5 ,那么 EMQ X 使用 MD5 算法對 secrettest_password 字符串加密

本文采用第一種配置方式,將得到的 MD5 密文插入表 mqtt_user。讀者可以通過在線的 MD5 工具或者自己寫程序對密碼進行編碼。

MD5("test_passwordsecret") -> a904b2d1d2b2f73de384955022964595
mysql> INSERT INTO mqtt_user(username,password_hash,salt) VALUES('test_username', 'a904b2d1d2b2f73de384955022964595', 'secret');

Query OK, 1 row affected (0.00 sec)

mysql> select * from mqtt_user;
+----+----------------+----------------------------------+--------+--------------+---------+
| id | username       | password_hash                    | salt   | is_superuser | created |
+----+----------------+----------------------------------+--------+--------------+---------+
|  3 | test_username1 | a904b2d1d2b2f73de384955022964595 | secret |            0 | NULL    |
+----+----------------+----------------------------------+--------+--------------+---------+
1 row in set (0.00 sec)

啟用認證功能

修改插件配置並啟用插件

修改 etc/plugins/emqx_auth_mysql.conf,修改后的有效配置如下所示,其余 ACL 相關的配置項可以注釋:

## 修改為實際 mysql 所在的服務器地址
auth.mysql.server = localhost:3306

## 修改為上面創建成功的 emqx 數據庫
auth.mysql.database = emqx

## 連接認證查詢語句
auth.mysql.auth_query = SELECT password_hash AS password, salt FROM mqtt_user WHERE username = '%u'

## 加密算法 plain | md5 | sha | sha256 | bcrypt
## 加鹽加密算法
auth.mysql.password_hash = md5,salt

## 不加鹽加密算法,直接寫算法名稱即可
# auth.mysql.password_hash = md5

修改完畢后使用 Dashboard 或命令行重啟插件以應用配置,命令行重啟示例如下:

emqx_ctl plugins reload emqx_auth_mysql
關閉匿名認證

EMQ X 默認開啟了匿名認證,即便啟用了認證功能,數據庫沒有查詢到數據時設備也能正常連接,只有當查詢到數據且密碼錯誤時才會拒絕連接。

打開 etc/emqx.conf 配置文件,禁用匿名認證:

## Value: true | false
allow_anonymous = false

重啟 emqx 完成配置應用。

測試

准備就緒后,僅通過認證校驗之后的設備才能成功連接到 EMQ X:

  1. 使用正確的用戶名和密碼進行連接,並訂閱 "topic" 主題,可以連接成功:
$ mosquitto_sub -p 1883 -u test_username -P test_password -t 'topic' -d
Client mosqsub|5228-wivwiv-mac sending CONNECT
Client mosqsub|5228-wivwiv-mac received CONNACK
Client mosqsub|5228-wivwiv-mac sending SUBSCRIBE (Mid: 1, Topic: topic, QoS: 0)
Client mosqsub|4119-zh
ouzibode received SUBACK
Subscribed (mid: 1): 0
  1. 使用錯誤的用戶名或密碼進行連接,並訂閱 "topic" 主題,連接失敗:
$ mosquitto_sub -p 1883 -u test_username -P test_password -t 'topic' -d
Client mosqsub/61879-wivwiv-ma sending CONNECT
Client mosqsub/61879-wivwiv-ma received CONNACK
Connection Refused: not authorised.

總 結

讀者在理解了 EMQ X MySQL 認證原理之后,可以結合 MySQL 拓展相關應用。歡迎關注 EMQ X 安全系列文章,后續本系列將依次講解 EMQ X 與物聯網安全相關問題,助您構建高安全物聯網項目。


免責聲明!

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



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