【问题标题】:Problems using paho mqtt client with python 3.7在 python 3.7 中使用 paho mqtt 客户端的问题
【发布时间】:2018-10-17 13:20:16
【问题描述】:

我正在运行以下代码以连接到 mqtt 服务器。

import paho.mqtt.client as mqtt
import ssl
import uuid

client = mqtt.Client(str(uuid.uuid1()))
client.tls_set(
    "ca.crt",
    "client.crt",
    "client.key",
    cert_reqs=ssl.CERT_REQUIRED,
    tls_version=ssl.PROTOCOL_TLSv1
)
client.connect(
    "127.0.0.1",
    8883,
)
client.loop_forever()

此代码适用于 python2.7 版本。但是当我使用 python3.7 版本运行它时,出现以下错误。

Traceback (most recent call last):
  File "test.py", line 29, in <module>
    8883,
  File "virtualenvs/mqtt-xG2h6zri/lib/python3.7/site-packages/paho/mqtt/client.py", line 839, in connect
    return self.reconnect()
  File "mqtt-xG2h6zri/lib/python3.7/site-packages/paho/mqtt/client.py", line 994, in reconnect
    sock.do_handshake()
  File ".pyenv/versions/3.7.0/lib/python3.7/ssl.py", line 1108, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: IP address mismatch, certificate is not valid for '127.0.0.1'. (_ssl.c:1045)

请帮我弄清楚如何在 python 3.7 中完成这项工作。

【问题讨论】:

  • 错误很明显,它表示代理提供的证书与您用于访问它的 IP 地址 (127.0.0.1) 不匹配。编辑问题以包含 openssl x509 -in server.crt -text 输出,其中 server.crt 是代理的证书。

标签: python ssl mqtt paho python-3.7


【解决方案1】:

找到答案了。

实际上,根据this链接匹配服务器IP地址与证书CN字段已被弃用超过15年。但是低于 3.7 的 python 版本仍然允许这样做,即使它已被弃用。因此,我必须在 SAN 字段中添加服务器的 IP 地址来创建证书。

this 回答中解释了使用 SAN 字段创建证书。但是答案中的解决方案使用了域名。如果您要使用 IP 地址创建证书,请使用此命令创建证书,而不是该答案中的命令。

openssl x509 -req -in server.csr \
        -extfile <(printf "subjectAltName=IP:127.0.0.1") \
        -CA ca.crt \
        -CAkey ca.key \
        -CAcreateserial -out server.crt \
        -days 365

使用这些证书后,错误就解决了。

【讨论】:

  • 那个尴尬的内联 printf 可以在更新的 openssl 版本中更改为:--addext 'subjectAltName=IP:127.0.0.1'
【解决方案2】:

有一个类似的问题(虽然使用 RabbitsMQ 客户端 Pika 而不是 MQTT),但是当尝试连接到外部端点而不是本地主机时,在 python 3.8 中的 do_handshake() 方法上,SSL 库中抛出了类似的错误,我无法生成新的 ssl 证书,因为它已提供给我。

接受的答案对我有所帮助,但我认为它可能对其他人有所帮助,因为降级到 python3.6 会提供更有用的错误消息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/root/miniconda/envs/venv3.6/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 359, in __init__
    self._impl = self._create_connection(parameters, _impl_class)
  File "/root/miniconda/envs/venv3.6/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 450, in _create_connection
    raise self._reap_last_connection_workflow_error(error)
  File "/root/miniconda/envs/venv3.6/lib/python3.6/site-packages/pika/adapters/utils/io_services_utils.py", line 636, in _do_ssl_handshake
    self._sock.do_handshake()
  File "/root/miniconda/envs/venv3.6/lib/python3.6/ssl.py", line 1077, in do_handshake
    self._sslobj.do_handshake()
  File "/root/miniconda/envs/venv3.6/lib/python3.6/ssl.py", line 694, in do_handshake
    match_hostname(self.getpeercert(), self.server_hostname)
  File "/root/miniconda/envs/venv3.6/lib/python3.6/ssl.py", line 331, in match_hostname
    % (hostname, dnsnames[0]))
ssl.CertificateError: hostname '149.176.221.21' doesn't match 'redacted.internal.url'

redacted.internal.url 是您必须为连接设置的主机名(在 ssl 上下文对象中),因为这是您证书上的任何内容。

这与您实际连接的 ip 地址/url 无关,在本例中是 149.176.221.21

【讨论】:

    【解决方案3】:

    我重新创建了服务器证书,其中 Common Name 字段作为服务器机器(安装 mosquitto 代理的位置)的“主机名”而不是 IP 地址。
    基本上是 x.x.x.x 主机名
    但是,它适用于 windows

    此外,如果有人使用 TLS 证书,将 tls_insecure_set() 设置为 true 并没有任何意义。

    【讨论】:

      【解决方案4】:

      这里写的信息对我帮助很大,经过大约2天的努力,我找到了解决办法。

      我为我的成功实验做了一个脚本。 希望它对您的业务有益。

      #!/bin/bash
      
      wd="`dirname $0`"
      if [ ! -z "$wd" ]; then
          if [ $wd == "." ];then wd=`pwd`;fi  
      fi
      
      certDir="${wd}/certs";
      conf_dir="/mosquitto/config" #WD
      
      rm -rf ${certDir} 
      
      mkdir -p ${certDir}
      
      cd ${certDir}
      
      
      #subjectAltName olmazsa self signet sertifika ile bağlanamıyor.
      #Server IP - Port bilgileri
      
      #~ IP="mqtt.eclipseprojects.io"
      
      IP="192.168.1.10"
      PORT="58883"
      
      SUBJECT_CA="/C=TR/ST=Istanbul/L=Istanbul/O=Example/OU=CA/CN=$IP"
      SUBJECT_SERVER="/C=TR/ST=Istanbul/L=Istanbul/O=Example/OU=server/CN=$IP"
      SUBJECT_CLIENT="/C=TR/ST=Istanbul/L=Istanbul/O=Example/OU=client/CN=$IP"
      
      MAX_DAYS=3650
       
      SB_NAME="subjectAltName = IP:127.0.0.1" #"subjectAltName=DNS:example.com,IP:$IP"
      space="################################################################################################################"
      
      function generate_CA () {
         echo -e "$SUBJECT_CA\n$space" 
         openssl req -x509 -nodes -sha256 -newkey rsa:2048 -subj "$SUBJECT_CA" -addext  "${SB_NAME}" -days ${MAX_DAYS} -keyout ca.key -out ca.crt 
         
      }
      
      function generate_server () {
          echo -e "$SUBJECT_SERVER\n$space"
      
          openssl req -nodes -sha256 -new -subj "$SUBJECT_SERVER" -keyout server.key -out server.csr -addext "${SB_NAME}"
      
          openssl x509 -req -in server.csr \
          -extfile <(printf "${SB_NAME}") \
          -CA ca.crt \
          -CAkey ca.key \
          -CAcreateserial -out server.crt \
          -days ${MAX_DAYS}
      }
      
      function generate_client () {
         echo -e "$SUBJECT_CLIENT\n$space"
         openssl req -new -nodes -sha256 -subj "$SUBJECT_CLIENT" -out client.csr -keyout client.key 
         openssl x509 -req -sha256 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days ${MAX_DAYS}
      }
      
      function clean () {
         echo -e "$SUBJECT_CLIENT\n$space"
          rm client.csr client.key client.crt 
          rm server.csr server.key server.crt 
          rm ca.srl ca.key ca.crt 
      }
      
      
      #~ clean
      
      generate_CA
      generate_server
      generate_client
      ############################################
      cd ${wd}
      
      echo "port ${PORT}
      
      #require_certificate true
      
      cafile ${conf_dir}/certs/ca.crt
      certfile ${conf_dir}/certs/server.crt
      keyfile ${conf_dir}/certs/server.key
      
      tls_version tlsv1.2
      
      use_identity_as_username true
      password_file ${conf_dir}/password.txt
      listener 1883
      
      persistence false
      persistence_location /mosquitto/data/
      
      " > mosquitto.conf
      
      
      
      echo "Use Examples
      #Server
      
      mosquitto -c ${certDir}/mosquitto.conf -v
      
      #Subcriber
      
      mosquitto_sub -h ${IP} -p ${PORT}  --cafile ${certDir}/ca.crt --cert ${certDir}/client.crt --key ${certDir}/client.key -t temperature
      
      #Publisher
      
      mosquitto_pub  -h ${IP} -p ${PORT} --cafile ${certDir}/ca.crt --cert ${certDir}/client.crt --key ${certDir}/client.key -t temperature -m test_message
      "
      

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      • 2020-01-18
      • 1970-01-01
      • 2017-04-22
      • 1970-01-01
      • 2019-12-22
      • 2018-10-18
      • 2018-08-31
      • 1970-01-01
      • 2018-03-17
      相关资源
      最近更新 更多