Tutoriels IoT

Python MQTT TLS : se connecter en toute sécurité sur le port 8883 avec paho-mqtt

Chiffrez votre trafic MQTT Python avec paho-mqtt et TLS sur le port 8883 : utilisez le magasin de CA du système, gardez la vérification du nom d'hôte active, corrigez les erreurs de certificat courantes et connectez-vous en WebSocket sécurisé quand seuls les ports web sont ouverts.

Cadenas au-dessus d'un script Python montrant une connexion Python MQTT TLS vers un broker sur le port 8883
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Python MQTT TLS, c'est la différence entre envoyer votre nom d'utilisateur, votre mot de passe et vos données de capteurs en clair sur Internet, et les envoyer chiffrés et authentifiés. Dans ce tutoriel, vous allez configurer paho-mqtt pour se connecter sur le port 8883 à l'aide des certificats CA de confiance de votre système d'exploitation, garder la vérification du nom d'hôte activée et corriger les erreurs de certificat qui bloquent la plupart des gens. Chaque exemple se connecte à broker.connectmq.com, qui présente un certificat Let's Encrypt reconnu publiquement : aucun fichier CA personnalisé n'est nécessaire.

Ce que TLS apporte à MQTT

MQTT n'intègre aucun chiffrement. Sur le port 1883, tout circule sous forme d'octets lisibles, y compris le paquet CONNECT contenant vos identifiants. TLS encapsule la connexion TCP et vous offre trois garanties :

  1. Confidentialité : personne sur le chemin réseau ne peut lire les payloads ni les mots de passe.
  2. Intégrité : personne ne peut modifier les messages en transit sans que cela soit détecté.
  3. Authentification du serveur : votre client vérifie qu'il parle bien au broker demandé, et non à un imposteur.

C'est ce troisième point que l'on désactive par mégarde. Le chiffrement sans vérification vous protège des écoutes passives, mais pas d'un attaquant actif qui présente son propre certificat. Le guide des bonnes pratiques de sécurité MQTT couvre la vue d'ensemble ; cet article se concentre sur la bonne configuration côté client.

ConnectMQ expose ces ports sur chaque broker :

Port Transport Chiffré Usage depuis Python
1883 MQTT sur TCP Non Tests locaux uniquement
8883 MQTT sur TLS Oui Choix par défaut en production
8083 MQTT sur WebSocket Non Rarement utile depuis Python
8084 MQTT sur WebSocket sécurisé, chemin /mqtt Oui Quand seuls les ports web sont autorisés

Prérequis

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

Vérifiez que le certificat du broker est validé depuis votre machine avant d'écrire la moindre ligne de Python. Cette commande affiche la chaîne et le résultat de la vérification :

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

Cherchez Verification: OK. Si OpenSSL échoue déjà à ce stade, le problème vient du magasin de CA de votre système ou du réseau, pas de votre code.

Le client Python MQTT TLS minimal

Enregistrez ceci sous tls_client.py et remplacez k7f3q2 par votre propre chaîne aléatoire :

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

# Utiliser les CA de confiance du système d'exploitation, exiger un certificat valide
# et vérifier qu'il correspond à BROKER. C'est le comportement sécurisé par défaut.
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()

Lancez-le : vous devriez voir quelque chose comme Connected over TLSv1.3 using TLS_AES_256_GCM_SHA384, suivi du retour de votre message.

Ce que fait tls_set()

Appelé sans argument ca_certs, tls_set() construit un contexte SSL qui charge les certificats de confiance par défaut de la plateforme, exige que le serveur présente un certificat valide et vérifie que le nom du certificat correspond à l'hôte passé à connect(). Les arguments explicites cert_reqs et tls_version ci-dessus correspondent aux valeurs par défaut ; ils sont écrits pour que l'intention soit évidente pour le prochain lecteur.

Si vous préférez garder un contrôle total, construisez le contexte vous-même et transmettez-le :

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

ssl.create_default_context() active la vérification du nom d'hôte et du certificat, et la définition d'une version minimale rejette les protocoles obsolètes. Utilisez soit tls_set(), soit tls_set_context(), mais pas les deux.

Ajouter des identifiants pour un broker privé

TLS protège les identifiants que vous envoyez : combinez donc toujours les deux. Avec un broker créé dans le portail 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)

Utilisez le nom d'hôte et le client ID affichés dans le portail ; le broker associe les client IDs aux identifiants qu'il délivre. Chargez les secrets depuis des variables d'environnement (os.environ["MQTT_PASSWORD"]) plutôt que de les committer dans votre gestionnaire de sources.

WebSocket sécurisé depuis Python

Certains réseaux bloquent tout sauf les ports web standard. paho peut faire transiter MQTT par un WebSocket sécurisé sur le port 8084, avec la même vérification 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)

Tout le reste, callbacks, abonnements et publication, reste identique. L'article MQTT sur WebSocket explique quand ce transport est pertinent.

Corriger les erreurs TLS courantes

La plupart des échecs TLS se résument à une poignée de causes. Faites correspondre votre message d'erreur à ce tableau :

Erreur Cause probable Correction
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate Python ne trouve pas les CA de confiance Voir les corrections du magasin de CA ci-dessous
Hostname mismatch, certificate is not valid for '...' Connexion par adresse IP ou par un alias Se connecter avec le nom d'hôte exact du broker
certificate is not yet valid ou certificate has expired L'horloge de l'appareil est fausse Synchroniser l'heure par NTP avant la connexion
WRONG_VERSION_NUMBER Client TLS qui parle au port en clair 1883 Utiliser le port 8883
La connexion se fige puis expire Client en clair qui parle au port TLS 8883, ou port bloqué Appeler tls_set(), ou essayer le port 8084

Corriger un magasin de CA manquant

  • macOS avec Python de python.org : cette version de Python n'a pas accès au trousseau système. Exécutez le script « Install Certificates.command » du dossier de l'application Python, ou pointez paho vers certifi : pip install certifi, puis client.tls_set(ca_certs=certifi.where()).
  • Images Docker allégées : installez le bundle de CA, par exemple apt-get install -y ca-certificates sur les images basées sur Debian.
  • Réseaux d'entreprise avec inspection TLS : un proxy peut remplacer les certificats par les siens. Demandez au service informatique la CA racine de l'entreprise et passez-la avec ca_certs= plutôt que de désactiver la vérification.
  • Linux embarqué : mettez à jour le bundle de CA ; les images très anciennes peuvent ne pas inclure le certificat ISRG Root X1 auquel se rattache Let's Encrypt.

Ne jamais « corriger » TLS en désactivant la vérification

Vous trouverez des conseils recommandant d'appeler client.tls_insecure_set(True) ou de passer cert_reqs=ssl.CERT_NONE. Les deux font disparaître l'erreur en acceptant n'importe quel certificat de n'importe qui, ce qui supprime silencieusement l'authentification du serveur. Ne les utilisez que pour un diagnostic rapide sur votre propre réseau de test, jamais dans du code déployé.

Évitez aussi d'épingler (pinning) le certificat feuille du broker dans votre client. Les certificats Let's Encrypt sont renouvelés régulièrement, donc un certificat épinglé cassera au prochain renouvellement. Faites plutôt confiance à la CA, ce que fait le magasin par défaut.

Checklist de production

Avant de déployer un client Python utilisant TLS, vérifiez chaque point :

  1. Le port 8883 (ou 8084 avec WebSocket) est utilisé partout ; rien ne se rabat sur 1883.
  2. tls_set() ou tls_set_context() est appelé sans tls_insecure_set(True).
  3. Le client se connecte par nom d'hôte, jamais par adresse IP.
  4. L'appareil garde une heure exacte, synchronisée par NTP au démarrage.
  5. Le bundle de CA de l'appareil est maintenu et mis à jour avec le système.
  6. Les identifiants proviennent de variables d'environnement ou d'un coffre de secrets.
  7. Une logique de reconnexion est en place ; le guide de reconnexion paho-mqtt présente un modèle robuste.

Pour aller plus loin

Si vous débutez avec paho, le tutoriel paho mqtt python couvre les bases du publish et du subscribe, et le guide aiomqtt et asyncio montre comment passer un tls_context à un client asynchrone. Pour les clients dans d'autres langages, le panorama des bibliothèques clientes MQTT compare la prise en charge de TLS selon les écosystèmes. La documentation du module ssl de Python est la référence pour chaque option de contexte utilisée ici.

Sécurisez votre trafic MQTT avec ConnectMQ

ConnectMQ est un broker MQTT managé avec TLS sur le port 8883 et WebSocket sécurisé sur le port 8084 activés d'emblée, adossés à un certificat Let's Encrypt géré automatiquement : vos clients Python vérifient le broker avec le magasin de CA dont ils disposent déjà. Testez sur le serveur MQTT public gratuit (réservé aux tests, pas aux données de production), puis passez à un broker MQTT cloud privé avec des identifiants générés. Créez votre broker gratuit sur le plan Serverless, sans carte bancaire.

Questions fréquentes

Dois-je télécharger un certificat CA pour me connecter avec TLS ?

Non. Le broker utilise un certificat Let's Encrypt rattaché à une racine reconnue par les systèmes d'exploitation actuels, donc tls_set() avec le magasin de CA par défaut fonctionne.

Quel port utilise MQTT sur TLS ?

Le port standard est 8883. ConnectMQ propose aussi MQTT sur WebSocket sécurisé sur le port 8084 avec le chemin /mqtt.

Pourquoi Python MQTT TLS échoue-t-il quand je me connecte par adresse IP ?

La vérification du nom d'hôte compare le nom du certificat à l'hôte auquel vous vous êtes connecté. Une adresse IP ne correspond pas au nom du broker, donc la vérification échoue par conception ; utilisez le nom d'hôte.

TLS suffit-il à sécuriser mon client MQTT ?

TLS protège la connexion, mais il vous faut toujours des identifiants robustes et propres à chaque appareil, ainsi qu'une conception soignée des topics. Combinez TLS avec des identifiants uniques issus du portail du broker.

Articles liés

Les meilleurs outils CLI MQTT pour tester, scripter et déboguer

Un comparatif pratique de mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, la CLI MQTT.js, curl et mqttui, avec le même test exécuté sur le serveur MQTT public gratuit broker.connectmq.com pour choisir le bon outil pour le scripting et le débogage.

9 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.