百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

mqtt实战-EMQX MQTT 服务器启用 SSL/TLS 安全连接

bigegpt 2024-08-01 11:54 10 浏览

大家好,我是yangyang.本计划不会最近不会更新mq相关文章,奈何今天使用tls连接生成证书的时候遇到了一个坑,于是,给大家分享一下.

SSL/TLS 证书准备

通常来说,我们会需要数字证书来保证 TLS 通讯的强认证。数字证书的使用本身是一个三方协议,除了通讯双方,还有一个颁发证书的受信第三方,有时候这个受信第三方就是一个 CA。和 CA 的通讯,一般是以预先发行证书的方式进行的。也就是在开始 TLS 通讯的时候,我们需要至少有 2 个证书,一个 CA 的,一个 EMQX 的,EMQX 的证书由 CA 颁发,并用 CA 的证书验证。

获得一个真正受外界信任的证书需要到证书服务提供商进行购买。在实验室环境,我们也可以用自己生成的证书来模拟这个过程。下面我们分别以这两种方式来说明 EMQX 服务器的 SSL/TLS 启用过程。

注意: 购买证书与自签名证书的配置,读者根据自身情况只需选择其中一种进行测试。


购买证书

如果有购买证书的话,就不需要自签名证书。

为方便 EMQX 配置,请将购买的证书文件重命名为 emqx.crt,证书密钥重命名为 emqx.key

自签名证书

在这里,我们假设您的系统已经安装了 OpenSSL。使用 OpenSSL 附带的工具集就可以生成我们需要的证书了。

首先,我们需要一个自签名的 CA 证书。生成这个证书需要有一个私钥为它签名,可以执行以下命令来生成私钥:

openssl genrsa -out ca.key 2048

这个命令将生成一个密钥长度为 2048 的密钥并保存在 ca.key 中。有了这个密钥,就可以用它来生成 EMQX 的根证书了:

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

查看 CA 证书信息(可选):

openssl x509 -in ca.pem -noout -text

根证书是整个信任链的起点,如果一个证书的每一级签发者向上一直到根证书都是可信的,那个我们就可以认为这个证书也是可信的。有了这个根证书,我们就可以用它来给其他实体签发实体证书了。

实体(在这里指的是 EMQX)也需要一个自己的私钥对来保证它对自己证书的控制权。生成这个密钥的过程和上面类似:

openssl genrsa -out emqx.key 2048

新建 openssl.cnf 文件,

  • req_distinguished_name :根据情况进行修改,
  • alt_names: BROKER_ADDRESS 修改为 EMQX 服务器实际的 IP 或 DNS 地址,例如:IP.1 = 127.0.0.1,或 DNS.1 = broker.xxx.com (如果在内网测试发现连不上,可以本地host `127.0.0.1 borker.test.com` 然后这里就写:IP.1=127.0.0.1 DNS.1=borker.test.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 = Zhejiang
localityName = Hangzhou
organizationName = EMQX
commonName = Server certificate
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = BROKER_ADDRESS
DNS.1 = BROKER_ADDRESS

然后以这个密钥和配置签发一个证书请求:

openssl req -new -key ./emqx.key -config openssl.cnf -out emqx.csr

然后以根证书来签发 EMQX 的实体证书:

openssl x509 -req -in ./emqx.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out emqx.pem -days 3650 -sha256 -extensions v3_req -extfile openssl.cnf

查看 EMQX 实体证书(可选):

openssl x509 -in emqx.pem -noout -text

验证 EMQX 实体证书,确定证书是否正确:

$ openssl verify -CAfile ca.pem emqx.pem
emqx.pem: OK

准备好证书后,我们就可以启用 EMQX 的 TLS/SSL 功能了。

SSL/TLS 启用及验证

在 EMQX 中 mqtt:ssl 的默认监听端口为 8883。




MQTT 连接测试


意:自签证书必须要传递ca根证书,同时如果emqx开启客户端证书验证时,如果上传了客户端证书和key就必须要传入对的或者不传.购买证书直接选第一个证书类型.

php workerman/mqtt 接入代码

   public function onWorkerStart(Worker $worker)
    {
        $mqttConfig = config('mqtt.fbox');
        if (empty($mqttConfig['listen'])) {
            return;
        }

        $options = [];
        !empty($mqttConfig['username']) && $options['username'] = $mqttConfig['username'];
        !empty($mqttConfig['password']) && $options['password'] = $mqttConfig['password'];
        if (0 === strpos($mqttConfig['listen'], 'mqtts') || 0 === strpos($mqttConfig['listen'], 'wss') ) {
            if (empty($mqttConfig['ssl_ca'])) {
                echo '[FBOX]', '请申请并配置证书', PHP_EOL;
                return;
            }

            $verifyPeer = false;
            $allowSelfSigned = false;
            if ($mqttConfig['ssl_ca_type'] === 'selfSign') {
                $verifyPeer = true;
                $allowSelfSigned = true;
            }


            $options['ssl'] = [
                'verify_peer' => $verifyPeer, // 如果是自签名证书需要设置为true,因为需要验证根证书,自行购买不用
                'allow_self_signed' => $allowSelfSigned,
                'cafile' => $mqttConfig['ssl_ca']
            ];
            if (!empty($mqttConfig['ssl_key'])) {
                $options['ssl']['local_pk'] = $mqttConfig['ssl_key'];
            }

            if (!empty($mqttConfig['ssl_cert'])) {
                $options['ssl']['local_cert'] = $mqttConfig['ssl_cert'];
            }
        }

        $this->connectMQTT($mqttConfig['listen'], $options);
    }
    
    protected function connectMQTT(string $addr, array $options = [])
    {
        // TODO: Implement connectMQTT() method.
        $this->client = new Client($addr, $options);
        $this->client->onConnect = [$this, 'onMqttConnect'];
//        $this->client->onReconnect =  [$this, 'onMqttReConnect'];
        $this->client->onMessage = [$this, 'onMqttMessage'];
        $this->client->onError = [$this, 'onMqttError'];
        $this->client->connect();
    }

nodejs mqtt 接入代码

const mqtt = require('mqtt')
/* 
  choose which protocol to use for connection here 
*/
// const { connectOptions } = require('./use_mqtt.js')
const { connectOptions } = require('./use_mqtts.js')
// const { connectOptions } = require('./use_ws.js')
// const { connectOptions } = require('./use_wss.js')

/**
 * this demo uses EMQX Public MQTT Broker (https://www.emqx.com/en/mqtt/public-mqtt5-broker), here are the details:
 *
 * Broker host: broker.emqx.io
 * TCP Port: 1883
 * SSL/TLS Port: 8883
 * WebSocket port: 8083
 * WebSocket over TLS/SSL port: 8084
 */

const clientId = 'emqx_nodejs_' + Math.random().toString(16).substring(2, 8)
const options = {
  clientId,
  clean: true,
  connectTimeout: 4000,
  /**
   * By default, EMQX allows clients to connect without authentication.
   * https://docs.emqx.com/en/enterprise/v4.4/advanced/auth.html#anonymous-login
   */
  username: 'emqx_test',
  password: 'emqx_test',
  reconnectPeriod: 1000,
  // Enable the SSL/TLS, whether a client verifies the server's certificate chain and host name
  rejectUnauthorized: true,
  // for more options and details, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options
}

const { protocol, host, port } = connectOptions
/**
 * if protocol is "mqtt", connectUrl = "mqtt://broker.emqx.io:1883"
 * if protocol is "mqtts", connectUrl = "mqtts://broker.emqx.io:8883"
 * if protocol is "ws", connectUrl = "ws://broker.emqx.io:8083/mqtt"
 * if protocol is "wss", connectUrl = "wss://broker.emqx.io:8084/mqtt"
 *
 * for more details about "mqtt.connect" method & options,
 * please refer to https://github.com/mqttjs/MQTT.js#mqttconnecturl-options
 */
let connectUrl = `${protocol}://${host}:${port}`
if (['ws', 'wss'].includes(protocol)) {
  // mqtt: MQTT-WebSocket uniformly uses /path as the connection path,
  // which should be specified when connecting, and the path used on EMQX is /mqtt.
  connectUrl += '/mqtt'
}

/**
 * If you are using mutual (two-way) TLS authentication, you need to pass the CA, client certificate, and client private key.
 */
if (['mqtts', 'wss'].includes(protocol)) {
  options['ca'] = fs.readFileSync('./path/to/your/ca.crt')
  options['key'] = fs.readFileSync('./path/to/your/client.key')
  options['cert'] = fs.readFileSync('./path/to/your/client.crt')
}

const client = mqtt.connect(connectUrl, options)

const topic = '/nodejs/mqtt'
const payload = 'nodejs mqtt test'
// https://github.com/mqttjs/MQTT.js#qos
const qos = 0

// https://github.com/mqttjs/MQTT.js#event-connect
client.on('connect', () => {
  console.log(`${protocol}: Connected`)

  // subscribe topic
  // https://github.com/mqttjs/MQTT.js#mqttclientsubscribetopictopic-arraytopic-object-options-callback
  client.subscribe(topic, { qos }, (error) => {
    if (error) {
      console.log('subscribe error:', error)
      return
    }
    console.log(`${protocol}: Subscribe to topic '${topic}'`)
    // publish message
    // https://github.com/mqttjs/MQTT.js#mqttclientpublishtopic-message-options-callback
    client.publish(topic, payload, { qos }, (error) => {
      if (error) {
        console.error(error)
      }
    })
  })
})

// https://github.com/mqttjs/MQTT.js#event-reconnect
client.on('reconnect', (error) => {
  console.log(`Reconnecting(${protocol}):`, error)
})

// https://github.com/mqttjs/MQTT.js#event-error
client.on('error', (error) => {
  console.log(`Cannot connect(${protocol}):`, error)
})

// https://github.com/mqttjs/MQTT.js#event-message
client.on('message', (topic, payload) => {
  console.log('Received Message:', topic, payload.toString())
})

相关推荐

当Frida来“敲”门(frida是什么)

0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...

服务端性能测试实战3-性能测试脚本开发

前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...

Springboot整合Apache Ftpserver拓展功能及业务讲解(三)

今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...

Linux和Windows下:Python Crypto模块安装方式区别

一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...

Python 3 加密简介(python des加密解密)

Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...

怎样从零开始编译一个魔兽世界开源服务端Windows

第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...

附1-Conda部署安装及基本使用(conda安装教程)

Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...

如何配置全世界最小的 MySQL 服务器

配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...

如何使用Github Action来自动化编译PolarDB-PG数据库

随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...

面向NDK开发者的Android 7.0变更(ndk android.mk)

订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...

信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要

问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...

OpenSSH 安全漏洞,修补操作一手掌握

1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...

Linux:lsof命令详解(linux lsof命令详解)

介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...

幻隐说固态第一期:固态硬盘接口类别

前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...

新品轰炸 影驰SSD多款产品登Computex

分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...