4. MQTT over SSL/TLS安全连接

任务目标

为MQTT网关启用SSL/TLS加密通信,使客户端通过加密通道连接网关,并验证服务端证书的有效性。本案例使用Mosquitto作为MQTT Broker,通过自签名证书实现TLS握手与加密数据传输。

环境准备

  • 操作系统:Linux(Ubuntu/Debian)或Windows(需安装OpenSSL)
  • Mosquitto Broker:sudo apt install mosquitto mosquitto-clients
  • OpenSSL工具链:sudo apt install openssl

证书生成

使用OpenSSL生成CA证书和服务端证书。以下命令在终端中依次执行:

# 1. 生成CA私钥和自签名CA证书
openssl req -new -x509 -days 365 -keyout ca.key -out ca.crt -subj "/CN=MQTT-CA"

# 2. 生成服务端私钥
openssl genrsa -out server.key 2048

# 3. 生成服务端证书签名请求(CSR)
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"

# 4. 使用CA签发服务端证书(添加SAN扩展以支持IP连接)
echo "subjectAltName=IP:127.0.0.1,DNS:localhost" > ext.cnf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 365 -extfile ext.cnf

Mosquitto SSL/TLS配置

创建配置文件 mosquitto-ssl.conf:

# MQTT over SSL/TLS 配置
listener 8883
protocol mqtt

# 证书文件路径
cafile /path/to/ca.crt
certfile /path/to/server.crt
keyfile /path/to/server.key

# 要求客户端提供证书(双向认证),若仅需服务端认证可设为false
require_certificate false

# 允许匿名访问(测试用),生产环境建议配置密码文件
allow_anonymous true

启动Broker:mosquitto -c mosquitto-ssl.conf

客户端连接测试

使用mosquitto_pub/sub验证加密连接。客户端需指定CA证书以验证服务端身份:

# 订阅测试(终端1)
mosquitto_sub -h localhost -p 8883 --cafile ca.crt -t "test/topic" -v

# 发布测试(终端2)
mosquitto_pub -h localhost -p 8883 --cafile ca.crt -t "test/topic" -m "Hello SSL"

验证方法与判定标准

  1. 连接成功:订阅端收到 test/topic Hello SSL 消息,说明TLS握手成功且数据传输加密。
  2. 证书验证生效:去掉 --cafile 参数重新连接,连接应失败并报错 certificate verify failed,证明客户端确实校验了服务端证书。
  3. 加密性确认:使用Wireshark抓包8883端口流量,观察TLS协议数据包(ClientHello/ServerHello/Application Data),无法直接看到明文消息内容。

常见问题

  • 证书CN不匹配:客户端连接时使用IP地址,但证书CN为localhost,需在生成CSR时添加SAN扩展(已在上述命令中包含)。
  • 权限错误:确保mosquitto用户对证书文件有读取权限:chmod 644 server.crt ca.crt,私钥chmod 600 server.key。
  • 端口占用:若8883被占用,可改用其他端口并同步修改客户端连接参数。

关键代码说明

本案例核心在于证书链的信任关系:客户端内置CA证书(ca.crt),Broker出示由该CA签发的服务端证书(server.crt)。TLS握手时客户端验证服务端证书的签名链和有效期,验证通过后建立加密通道。上述配置中require_certificate false表示仅服务端认证,适用于网关对设备单向认证的场景;若需设备身份认证,可设为true并额外为每个设备签发客户端证书。