Tutoriais de IoT

Python MQTT TLS: Conexão Segura na Porta 8883 com paho-mqtt

Criptografe o tráfego MQTT do seu Python com paho-mqtt e TLS na porta 8883: use o repositório de CAs do sistema, mantenha a verificação de hostname ativa, corrija os erros de certificado mais comuns e conecte via WebSocket seguro quando só portas web estiverem liberadas.

Cadeado sobre um script Python mostrando uma conexão python mqtt tls com um broker na porta 8883
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

TLS com MQTT em Python é a diferença entre mandar o seu usuário, a sua senha e os dados dos seus sensores pela internet em texto puro e mandá-los criptografados e autenticados. Neste tutorial você vai configurar o paho-mqtt para conectar na porta 8883 usando os certificados CA confiáveis do seu sistema operacional, manter a verificação de hostname ativada e corrigir os erros de certificado que travam a maioria das pessoas. Todos os exemplos se conectam ao broker.connectmq.com, o servidor MQTT público da ConnectMQ para testes, que serve um certificado Let's Encrypt publicamente confiável, então nenhum arquivo de CA personalizado é necessário.

O que o TLS faz pelo MQTT

O MQTT em si não tem criptografia. Na porta 1883 tudo, inclusive o pacote CONNECT com as suas credenciais, trafega como bytes legíveis. O TLS envolve a conexão TCP e oferece três garantias:

  1. Confidencialidade: ninguém no caminho da rede consegue ler payloads ou senhas.
  2. Integridade: ninguém consegue alterar mensagens em trânsito sem ser detectado.
  3. Autenticação do servidor: o seu cliente verifica que está realmente falando com o broker que pediu, e não com um impostor.

O terceiro ponto é o que as pessoas desativam sem querer. Criptografia sem verificação protege contra bisbilhoteiros passivos, mas não contra um atacante ativo que apresenta o próprio certificado. O guia de boas práticas de segurança MQTT cobre o panorama completo; este artigo se concentra em acertar o lado do cliente.

O ConnectMQ expõe estas portas em todos os brokers:

Porta Transporte Criptografada Uso a partir do Python
1883 MQTT sobre TCP Não Apenas testes locais
8883 MQTT sobre TLS Sim Padrão para produção
8083 MQTT sobre WebSocket Não Raramente necessária no Python
8084 MQTT sobre WebSocket seguro, caminho /mqtt Sim Quando só portas web são permitidas

Pré-requisitos

python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install "paho-mqtt>=2.0"

Antes de escrever qualquer linha de Python, verifique se o certificado do broker é validado a partir da sua máquina. Este comando mostra a cadeia e o resultado da verificação:

openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -brief </dev/null

Procure por Verification: OK. Se o OpenSSL já falhar aqui, o problema está no repositório de CAs do seu sistema ou na rede, não no seu código.

O cliente mínimo de MQTT com TLS em Python

Salve isto como tls_client.py e troque k7f3q2 por uma string aleatória sua:

import ssl
import time
import uuid

import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PORT = 8883
TOPIC = "connectmq/demo/k7f3q2/secure"


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connect failed: {reason_code}")
        return
    sock = client.socket()
    print(f"Connected over {sock.version()} using {sock.cipher()[0]}")
    client.subscribe(TOPIC, qos=1)


def on_message(client, userdata, msg):
    print(f"{msg.topic}: {msg.payload.decode()}")


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"tls-{uuid.uuid4().hex[:8]}")
client.on_connect = on_connect
client.on_message = on_message

# Usa as CAs confiáveis do sistema operacional, exige um certificado válido
# e verifica se ele corresponde a BROKER. Este é o padrão seguro.
client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLS_CLIENT)

client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
time.sleep(2)
client.publish(TOPIC, "hello over TLS", qos=1)
time.sleep(2)
client.disconnect()
client.loop_stop()

Execute e você deverá ver algo como Connected over TLSv1.3 using TLS_AES_256_GCM_SHA384, seguido da sua mensagem voltando.

O que o tls_set() faz

Chamado sem o argumento ca_certs, o tls_set() monta um contexto SSL que carrega os certificados confiáveis padrão da plataforma, exige que o servidor apresente um certificado válido e confere se o nome do certificado corresponde ao host passado para connect(). Os argumentos explícitos cert_reqs e tls_version acima são os valores padrão, escritos para deixar a intenção óbvia para quem ler o código depois.

Se preferir controle total, monte o contexto você mesmo e entregue-o ao cliente:

context = ssl.create_default_context()
context.minimum_version = ssl.TLSVersion.TLSv1_2
client.tls_set_context(context)

ssl.create_default_context() ativa a checagem de hostname e a verificação de certificado, e definir uma versão mínima rejeita protocolos legados. Use tls_set() ou tls_set_context(), não os dois.

Adicionando credenciais para um broker privado

O TLS protege as credenciais que você envia, então sempre combine os dois. Com um broker criado no portal do ConnectMQ:

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()
client.connect("broker.connectmq.com", 8883, keepalive=60)

Use o nome de host e o client ID exibidos no portal; o broker vincula os client IDs às credenciais que emite. Carregue os segredos de variáveis de ambiente (os.environ["MQTT_PASSWORD"]) em vez de enviá-los ao controle de versão.

WebSocket seguro a partir do Python

Algumas redes bloqueiam tudo, exceto as portas web padrão. O paho consegue tunelar o MQTT por WebSocket seguro na porta 8084, com a mesma verificação TLS:

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=f"wss-{uuid.uuid4().hex[:8]}",
    transport="websockets",
)
client.ws_set_options(path="/mqtt")
client.tls_set()
client.connect("broker.connectmq.com", 8084, keepalive=60)

Todo o resto, callbacks, assinaturas e publicação, continua igual. O artigo sobre MQTT sobre WebSocket explica quando esse transporte faz sentido.

Corrigindo erros comuns de TLS

A maioria das falhas de TLS se resume a poucas causas. Associe a sua mensagem de erro a esta tabela:

Erro Causa provável Correção
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate O Python não encontra as CAs confiáveis Veja as correções do repositório de CAs abaixo
Hostname mismatch, certificate is not valid for '...' Você conectou por endereço IP ou por um alias Conecte com o nome de host exato do broker
certificate is not yet valid ou certificate has expired O relógio do dispositivo está errado Sincronize a hora com NTP antes de conectar
WRONG_VERSION_NUMBER Cliente TLS falando com a porta 1883 sem criptografia Use a porta 8883
A conexão trava e depois estoura o timeout Cliente sem TLS falando com a porta TLS 8883, ou porta bloqueada Chame tls_set() ou tente a porta 8084

Corrigindo um repositório de CAs ausente

  • macOS com Python do python.org: esse Python vem sem acesso ao keychain do sistema. Execute o script "Install Certificates.command" na pasta do aplicativo Python ou aponte o paho para o certifi: pip install certifi e depois client.tls_set(ca_certs=certifi.where()).
  • Imagens Docker enxutas: instale o pacote de CAs, por exemplo apt-get install -y ca-certificates em imagens baseadas em Debian.
  • Redes corporativas com inspeção TLS: um proxy pode substituir os certificados pelos dele. Peça à TI a CA raiz corporativa e passe-a com ca_certs= em vez de desativar a verificação.
  • Linux embarcado: atualize o pacote de CAs; imagens muito antigas podem não incluir o certificado ISRG Root X1, ao qual a cadeia do Let's Encrypt se liga.

Nunca "corrija" o TLS desligando a verificação

Você vai encontrar conselhos para chamar client.tls_insecure_set(True) ou passar cert_reqs=ssl.CERT_NONE. Os dois fazem o erro sumir aceitando qualquer certificado de qualquer um, o que remove silenciosamente a autenticação do servidor. Use-os apenas para um diagnóstico rápido na sua própria rede de laboratório, nunca em código implantado.

Evite também fixar (pinning) o certificado folha do broker no cliente. Os certificados Let's Encrypt são renovados regularmente, então um certificado fixado vai quebrar na próxima renovação. Confie na CA, que é o que o repositório padrão faz.

Checklist de produção

Antes de implantar um cliente Python que usa TLS, confirme cada item:

  1. A porta 8883 (ou a 8084 com WebSocket) é usada em todo lugar; nada recorre à 1883.
  2. tls_set() ou tls_set_context() é chamado sem tls_insecure_set(True).
  3. O cliente conecta pelo nome de host, nunca por endereço IP.
  4. O dispositivo mantém a hora correta, sincronizada por NTP na inicialização.
  5. O pacote de CAs do dispositivo é mantido e atualizado junto com o sistema operacional.
  6. As credenciais vêm de variáveis de ambiente ou de um cofre de segredos.
  7. Há lógica de reconexão; o guia de reconexão do paho-mqtt mostra um padrão robusto.

Próximos passos

Se você é novo no paho, o tutorial de Paho MQTT em Python cobre o básico de publish e subscribe, e o guia de aiomqtt e asyncio mostra como passar um tls_context para um cliente assíncrono. Para clientes em outras linguagens, a visão geral de bibliotecas de cliente MQTT compara o suporte a TLS entre ecossistemas. A documentação do módulo ssl do Python é a referência de cada opção de contexto usada aqui.

Proteja o seu tráfego MQTT com o ConnectMQ

O ConnectMQ é um broker MQTT gerenciado com TLS na 8883 e WebSocket seguro na 8084 ativados desde o início, com um certificado Let's Encrypt gerenciado automaticamente, para que os seus clientes Python verifiquem o broker com o repositório de CAs que já têm. Teste no servidor MQTT público e depois migre para um broker MQTT na nuvem privado com credenciais geradas. Crie o seu broker gratuito no plano Serverless, sem cartão de crédito.

Perguntas frequentes

Preciso baixar um certificado CA para conectar com TLS?

Não. O broker usa um certificado Let's Encrypt cuja cadeia leva a uma raiz confiável nos sistemas operacionais atuais, então tls_set() com o repositório de CAs padrão funciona.

Qual porta o MQTT sobre TLS usa?

A porta padrão é a 8883. O ConnectMQ também oferece MQTT sobre WebSocket seguro na porta 8084, com o caminho /mqtt.

Por que o python mqtt tls falha quando conecto por endereço IP?

A verificação de hostname compara o nome do certificado com o host ao qual você se conectou. Um endereço IP não corresponde ao nome do broker, então a checagem falha por design; use o nome de host.

O TLS basta para proteger o meu cliente MQTT?

O TLS protege a conexão, mas você ainda precisa de credenciais fortes por dispositivo e de um design de topics cuidadoso. Combine o TLS com credenciais exclusivas geradas no portal do broker.

Artigos relacionados

Melhores Ferramentas CLI MQTT para Testes, Scripts e Depuração

Uma comparação prática entre mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, a CLI do MQTT.js, curl e mqttui, com o mesmo teste rodando no broker.connectmq.com, para você escolher a ferramenta certa para scripts e depuração.

9 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.