如何让Paho MQTT客户端信任自签名证书以实现TLS连接?
问题:Paho MQTT客户端无法连接使用自签名证书的Mosquitto Broker
我正在开展一个MQTT测试项目,搭建了需通过TLS运行的Mosquitto MQTT Broker,但因使用自签名证书,无法通过Paho MQTT客户端建立安全TLS连接。
证书生成步骤
我使用OpenSSL执行了以下步骤生成证书:
- 生成伪造CA签名密钥:
$ openssl genrsa -des3 -out ca.key 2048 - 生成伪造CA的证书签名请求:
$ openssl req -new -key ca.key -out ca.csr -sha256 - 创建伪造CA的根证书:
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 365 -sha256 - 创建服务器/MQTT Broker密钥对:
$ openssl genrsa -out server.key 2048 - 使用服务器密钥生成证书签名请求(通用名称设为Broker的特定IP):
$ openssl req -new -key server.key -out server.csr -sha256 - 以伪造CA身份签署服务器证书:
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360
Mosquitto配置
修改default.conf启用TLS:
listener 8883 cafile /etc/mosquitto/ca_certificates/ca.crt certfile /etc/mosquitto/certs/server.crt keyfile /etc/mosquitto/certs/server.key require_certificate true password_file /etc/mosquitto/passwd
客户端证书生成与Python代码
为实现双向认证,生成客户端证书:
- 创建客户端密钥对:
openssl genrsa -out client.key 2048 - 生成客户端证书签名请求:
openssl req -new -out client.csr -key client.key - 以伪造CA身份签署客户端证书:
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360
Python客户端代码:
import paho.mqtt.client as mqtt import ssl def on_message(client, userdata, msg): print(f"Received message '{msg.payload.decode()}' on topic '{msg.topic}'") def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected to MQTT Broker!") client.subscribe("test") else: print(f"Failed to connect, return code {rc}\n") client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message username = "x" password = "x" client.username_pw_set(username, password) client.tls_set(ca_certs="certs/ca.crt", certfile="certs/client.crt", keyfile="certs/client.key", tls_version=ssl.PROTOCOL_TLSv1_2) client.tls_insecure_set(False) # Ensure this is False for security broker_address = 'my_ip' port = 8883 client.connect(broker_address, port) client.loop_forever()
错误信息
执行脚本时出现以下错误:
mqtt_sub.py:17: DeprecationWarning: Callback API version 1 is deprecated, update to latest version client = mqtt.Client() Traceback (most recent call last): File "mqtt_sub.py", line 39, in <module> client.connect(broker_address, port) File "/home/lutz/.local/lib/python3.8/site-packages/paho/mqtt/client.py", line 1435, in connect return self.reconnect() File "/home/lutz/.local/lib/python3.8/site-packages/paho/mqtt/client.py", line 1598, in reconnect self._sock = self._create_socket() File "/home/lutz/.local/lib/python3.8/site-packages/paho/mqtt/client.py", line 4612, in _create_socket sock = self._ssl_wrap_socket(sock) File "/home/lutz/.local/lib/python3.8/site-packages/paho/mqtt/client.py", line 4671, in _ssl_wrap_socket ssl_sock.do_handshake() File "/usr/lib/python3.8/ssl.py", line 1338, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1145)
需求:如何让Paho MQTT库与自签名证书配合使用,或有哪些其他方案实现安全MQTT通信?
解决方案
1. 确认CA证书的信任配置
错误提示“self signed certificate”说明客户端未正确信任你生成的CA根证书:
- 检查
ca_certs参数的路径是否正确:建议使用绝对路径(如/home/user/certs/ca.crt)避免相对路径问题,确保文件是你生成的CA根证书。 - 将CA证书添加到客户端系统的信任根库:
- Linux:复制
ca.crt到/usr/local/share/ca-certificates/,执行update-ca-certificates更新信任列表。 - Windows:双击
ca.crt,选择安装到“受信任的根证书颁发机构”存储区。
- Linux:复制
2. 验证服务器证书的标识匹配
你将服务器证书的通用名称设为Broker的IP,需确保客户端连接时使用的broker_address与该IP完全一致,不能用主机名(除非证书包含主机名SAN字段):
- 若需用主机名连接,重新生成服务器证书并添加SAN字段:
创建server.cnf配置文件:
生成CSR:[req] distinguished_name = req_distinguished_name req_extensions = v3_req prompt = no [req_distinguished_name] CN = 192.168.1.100 # Broker的IP [v3_req] keyUsage = keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] IP.1 = 192.168.1.100 DNS.1 = broker.local # Broker的主机名openssl req -new -key server.key -out server.csr -sha256 -config server.cnf,再重新签署服务器证书。
3. 检查双向认证配置一致性
Mosquitto配置了require_certificate true,客户端必须提供信任CA签署的证书:
- 确认
client.crt是你的CA根证书签署的,且代码中certfile和keyfile路径正确。 - 若客户端密钥带密码(生成时用了
-des3),需在代码中添加密码参数,或重新生成无密码密钥:openssl genrsa -out client.key 2048。
4. 临时调试(禁止生产环境使用)
测试阶段可临时跳过服务器证书验证,但会降低安全性:
- 将
client.tls_insecure_set(True),此操作仅跳过服务器证书验证,双向认证仍生效。
替代安全方案
若自签名证书配置繁琐,可选择以下方案:
- Let's Encrypt证书:若Broker有公网域名,申请免费可信证书,客户端无需额外配置即可信任。
- 预共享密钥(PSK):Mosquitto支持PSK认证,无需证书,只需客户端与Broker共享密钥。示例配置:
客户端代码使用listener 8883 psk_hint hint psk_file /etc/mosquitto/psk.txtclient.tls_set_psk()方法配置PSK。
内容的提问来源于stack exchange,提问作者Lennart Lutz
相关产品推荐
相关产品推荐

