La sécurité MQTT se résume à une poignée de réflexes que la plupart des équipes connaissent, mais qu'elles sautent encore sous la pression des délais. Ce guide les transforme en une checklist en 12 points applicable à n'importe quel déploiement, avec du code à copier-coller pour vérifier le TLS en Python et en ligne de commande. Pour chaque point, nous indiquons aussi ce qu'un broker MQTT managé comme ConnectMQ fait déjà pour vous, et ce qui reste de votre ressort.
Pourquoi la sécurité MQTT mérite sa propre checklist
MQTT a été conçu pour être léger. Le protocole lui-même définit un champ nom d'utilisateur et un champ mot de passe dans le CONNECT, et laisse tout le reste (chiffrement, autorisation, protection contre les abus) au broker et à la couche réseau. Cette souplesse est précieuse pour les appareils contraints, mais elle signifie aussi qu'un déploiement MQTT n'est jamais plus sûr que son choix de configuration le plus faible.
Les défaillances typiques sont banales et évitables :
- Des appareils qui parlent TCP en clair sur le port 1883 à travers Internet.
- Un seul mot de passe partagé, gravé dans le firmware de chaque appareil.
- Des topics comme
customers/jane.doe@example.com/locationqui divulguent des données par leur seul nom. - Des abonnés qui font confiance à chaque payload et plantent (ou pire) sur une entrée malformée.
- Des clients qui « corrigent » une erreur TLS en désactivant la vérification des certificats.
Si vous découvrez la façon dont les brokers acheminent les messages, commencez par Qu'est-ce qu'un broker MQTT ? puis revenez ici.
La checklist de sécurité MQTT en un coup d'œil
| # | Pratique | Votre responsabilité | Ce que fournit ConnectMQ |
|---|---|---|---|
| 1 | Toujours utiliser TLS | Se connecter sur 8883 / 8084 | TLS sur 8883, WSS sur 8084, certificat Let's Encrypt |
| 2 | Garder les vraies données hors de la zone publique | Utiliser les identifiants du portail en production | Topics des tenants isolés de la zone publique |
| 3 | Des identifiants uniques par broker/appareil | Ne pas réutiliser un même mot de passe partout | Nom d'utilisateur, mot de passe et client ID générés par broker |
| 4 | Restreindre les client IDs | Utiliser l'ID émis et ses suffixes | Seuls le client ID émis et ses variantes _suffix sont acceptés |
| 5 | Stocker les secrets en sécurité sur les appareils | Stockage chiffré, pas de secrets dans Git | — |
| 6 | Concevoir des topics qui ne divulguent rien | Pas de données personnelles dans les noms de topics | Isolation multi-tenant |
| 7 | Valider chaque payload | Contrôles de schéma dans les abonnés | Limites de taille des messages par offre |
| 8 | Appliquer des limites de débit et des quotas | Brider les publishers | Quotas par offre, reason code 0x97 Quota exceeded |
| 9 | Se défendre contre la force brute et les rafales | Temporiser en cas d'échec | Blocage d'IP après des échecs d'authentification répétés, protection anti-rafales de connexions |
| 10 | Surveiller l'état des connexions | Alerter en cas de déconnexion inattendue | $SYS/broker/connection/{clientId}/state |
| 11 | Valider les certificats dans les clients | Ne jamais désactiver la vérification | Chaîne de certificats reconnue publiquement |
| 12 | Autoriser au niveau des topics | Séparer brokers ou applications selon les périmètres de confiance | Isolation au niveau du tenant |
La suite de l'article détaille chaque point.
1. Toujours utiliser TLS (ports 8883 et 8084)
Le MQTT en clair sur le port 1883 transmet noms d'utilisateur, mots de passe et payloads en texte clair. N'importe qui sur le chemin (le Wi-Fi d'un café, un routeur compromis, un port de switch en miroir) peut les lire et les rejouer. TLS règle ce problème en chiffrant la connexion et en prouvant l'identité du broker.
Sur ConnectMQ, chaque broker accepte :
- MQTT sur TLS sur
mqtts://broker.connectmq.com:8883 - MQTT sur WebSocket sécurisé sur
wss://broker.connectmq.com:8084/mqtt
Les deux utilisent un certificat Let's Encrypt, déjà reconnu par les magasins de confiance standard des systèmes d'exploitation. Réservez les ports 1883 et 8083 au développement. Les applications navigateur doivent de toute façon utiliser le WSS ; consultez MQTT sur WebSocket pour un exemple complet.
2. Ne jamais mettre de vraies données dans la zone publique
Le serveur MQTT public gratuit broker.connectmq.com propose une zone publique anonyme pour les expérimentations : connectez-vous sans nom d'utilisateur, avec un client ID unique, et vous pouvez publier et vous abonner immédiatement. C'est formidable pour apprendre, et c'est entièrement public. Quiconque s'abonne au bon topic peut lire vos messages.
Règles pour la zone publique :
- Utilisez un préfixe aléatoire comme
connectmq/demo/<your-random-id>/...pour éviter les collisions avec les autres. - Ne publiez jamais de données personnelles, d'identifiants, de localisations ni rien que vous ne posteriez pas sur un forum.
- Passez aux identifiants du portail avant d'impliquer de vrais utilisateurs ou de vrais appareils.
Les tenants authentifiés sur ConnectMQ sont isolés : leurs topics ne sont visibles ni par les autres tenants ni par la zone publique, et les clients publics ne voient que les autres clients publics. Plus de détails dans notre guide du serveur MQTT public gratuit.
3. Utiliser des identifiants uniques par broker et par appareil
Un mot de passe unique partagé par toute une flotte signifie qu'une seule image de firmware extraite compromet tous les appareils. Visez des identifiants révocables sans toucher au reste de la flotte.
Dans le portail ConnectMQ (https://app.connectmq.com), chaque broker que vous créez reçoit un nom d'utilisateur, un mot de passe et un client ID générés. Les secrets générés évitent les choix faibles classiques (admin/admin, iot123) et gardent les environnements séparés : créez un broker pour la préproduction et un autre pour la production plutôt que de partager les identifiants entre les deux.
Quel que soit le broker, renouvelez les identifiants lorsqu'un appareil est mis hors service et ne collez jamais de secrets de production dans des tickets, des messageries ou des captures d'écran.
4. Restreindre les client IDs
Le client ID MQTT identifie une session. Si n'importe qui peut se connecter avec n'importe quel client ID, un attaquant qui connaît l'ID d'un appareil peut le déconnecter (le broker ferme la session existante lorsqu'un ID en double se connecte) ou détourner sa session persistante.
ConnectMQ limite les connexions authentifiées au client ID émis pour le broker et à ses variantes _suffix. Si votre ID émis est YOUR_CLIENT_ID, vous pouvez connecter YOUR_CLIENT_ID_sensor1, YOUR_CLIENT_ID_dashboard, etc., mais pas des IDs arbitraires. Vous obtenez ainsi des noms de session prévisibles et traçables, et empêchez des inconnus d'usurper vos sessions.
Astuce pratique : dérivez le suffixe d'un élément stable de l'appareil, comme son numéro de série ou son adresse MAC, afin que les reconnexions réutilisent la même session.
5. Stocker les secrets en sécurité sur les appareils
Les identifiants doivent bien résider quelque part sur l'appareil. Rendez cet endroit aussi difficile d'accès que possible :
- Ne versionnez pas les identifiants dans le contrôle de source. Utilisez un en-tête de configuration ou un fichier d'environnement séparé et ignoré par Git.
- Utilisez le stockage protégé de la plateforme lorsqu'il existe (flash chiffrée / chiffrement NVS sur ESP32, TPM ou secure element sur les passerelles, gestionnaire de secrets sur les serveurs).
- Désactivez les ports de débogage et les consoles série dans le firmware de production pour que les secrets ne puissent pas être extraits trivialement.
- Prévoyez une étape de provisioning qui écrit des secrets propres à chaque appareil lors de la fabrication, au lieu de les compiler dans une image partagée.
6. Concevoir des topics qui ne divulguent pas d'informations
Les noms de topics sont des métadonnées, et les métadonnées fuient. Même avec des payloads chiffrés, un topic comme hospital/ward3/patient-4471/heart-rate en révèle beaucoup à quiconque peut l'observer.
Recommandations :
- Utilisez des identifiants opaques (
site-07/dev-3fa9/telemetry) plutôt que des noms, des e-mails ou des adresses. - Gardez une hiérarchie cohérente, par exemple
site/area/line/device/kind, pour que les permissions et les wildcards restent gérables. - Évitez les abonnements avec wildcard large comme
#dans les consommateurs de production ; abonnez-vous uniquement à ce dont vous avez besoin. - Limitez le nombre de niveaux. La zone publique, par exemple, autorise au maximum 8 niveaux de topic.
7. Valider chaque payload
Le broker transporte des octets ; il ne sait pas si votre JSON est bien formé ni si une température de 9 000 °C est plausible. Chaque abonné doit traiter les payloads entrants comme des données non fiables.
import json
ALLOWED_KEYS = {"temperature", "humidity", "ts"}
def parse_telemetry(raw: bytes):
if len(raw) > 4096:
raise ValueError("payload too large")
data = json.loads(raw.decode("utf-8"))
if not isinstance(data, dict) or not set(data) <= ALLOWED_KEYS:
raise ValueError("unexpected fields")
t = float(data["temperature"])
if not -40.0 <= t <= 125.0:
raise ValueError("temperature out of range")
return data
Rejetez, journalisez et passez à la suite. Ne transmettez jamais directement le contenu d'un payload à du SQL, à des commandes shell ou à du HTML. ConnectMQ impose des tailles maximales de message par offre (par exemple 256 Ko sur l'offre Serverless gratuite et 64 Ko dans la zone publique), ce qui plafonne le pire des cas, mais la validation de schéma reste votre affaire.
8. Appliquer des limites de débit et des quotas
Une boucle de firmware boguée qui publie aussi vite qu'elle le peut est une attaque par déni de service que vous avez écrite vous-même. Bridez côté appareil (publiez sur changement ou à intervalle fixe) et attendez-vous à ce que le broker impose lui aussi des limites.
ConnectMQ applique des quotas par offre et par zone. La zone publique autorise par exemple 10 messages par seconde et 10 abonnements par client. Lorsqu'un client MQTT 5 dépasse un quota, le broker répond avec le reason code 0x97 Quota exceeded ; en cas de forte charge, il peut répondre 0x89 Server busy. Traitez ces codes explicitement : temporisez, journalisez et alertez au lieu de réessayer en boucle serrée. Le guide des fonctionnalités de MQTT 5 détaille les reason codes.
9. Se protéger contre la force brute et les rafales de connexions
Les brokers exposés subissent en permanence des tentatives de devinette de mots de passe et des tempêtes de reconnexions. Sur ConnectMQ :
- Les adresses IP sont bloquées après des tentatives répétées avec de mauvais identifiants.
- Les rafales de connexions déclenchent des bannissements temporaires.
- Une protection adaptative contre la surcharge maintient la réactivité du cluster lors des pics.
Côté client, implémentez un backoff exponentiel avec gigue (jitter). Si toute une flotte se reconnecte au même instant après une micro-coupure réseau, même des appareils légitimes ressemblent à une attaque par rafale.
10. Surveiller l'état des connexions avec $SYS
On ne peut pas sécuriser ce qu'on ne voit pas. ConnectMQ publie l'état de connexion de chaque client sur $SYS/broker/connection/{clientId}/state : 1 lorsque le client se connecte et 0 lorsqu'il se déconnecte. Abonnez-vous depuis un service de supervision et alertez en cas de coupure inattendue ou d'appareil qui se connecte à des heures inhabituelles.
mosquitto_sub -h broker.connectmq.com -p 1883 -i monitor-7c2e \
-t '$SYS/broker/connection/my-device-7c2e/state' -v
# $SYS/broker/connection/my-device-7c2e/state 1
# $SYS/broker/connection/my-device-7c2e/state 0
Combinez cela avec les messages Last Will de MQTT pour que le reste de votre système soit informé des déconnexions non propres.
11. Valider les certificats dans chaque client
Un TLS sans validation de certificat, c'est du chiffrement vers un interlocuteur inconnu. Un attaquant placé au milieu peut présenter n'importe quel certificat, et le client lui enverra tranquillement ses identifiants. Malheureusement, « désactiver la vérification » est un correctif copié-collé courant pour les erreurs TLS.
Python (paho-mqtt 2.x avec le module ssl)
import ssl
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
ctx = ssl.create_default_context() # CA du système, vérification du nom d'hôte activée
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set_context(ctx)
client.on_connect = on_connect
client.connect("broker.connectmq.com", 8883)
client.loop_forever()
Ne livrez jamais ctx.check_hostname = False, ssl.CERT_NONE ou client.tls_insecure_set(True).
mosquitto_pub et mosquitto_sub
Sous Linux, indiquez à la CLI le répertoire des CA du système. Sur n'importe quelle plateforme, vous pouvez aussi télécharger le certificat ISRG Root X1 (isrgrootx1.pem) depuis Let's Encrypt et le passer avec --cafile :
# Linux : magasin de CA du système
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID_cli \
-t "site-07/#" -v
# Tout OS : certificat racine explicite
mosquitto_pub -h broker.connectmq.com -p 8883 --cafile isrgrootx1.pem \
-u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID_pub \
-t "site-07/dev-3fa9/telemetry" -m '{"temperature":22.5}'
Si le nom d'hôte ou la chaîne ne correspond pas, la connexion échoue. Cet échec est précisément la fonctionnalité recherchée.
12. Autoriser au niveau des topics là où c'est nécessaire
En règle générale avec MQTT, le principe du moindre privilège s'applique aux topics : un capteur de température ne devrait publier que sur son propre topic de télémétrie et ne s'abonner qu'à son propre topic de commandes. De nombreuses architectures l'imposent par des règles d'autorisation au niveau des topics, ou en plaçant les appareils de niveaux de confiance différents derrière des identifiants et des brokers distincts.
Avec ConnectMQ, le périmètre d'isolation est le tenant : les topics d'un tenant ne sont jamais visibles par un autre tenant ni par la zone publique. Si vous avez besoin d'une séparation stricte entre des groupes d'appareils, créez des brokers distincts pour eux dans le portail et conservez les contrôles applicatifs (qui peut envoyer quelle commande) dans votre backend.
Une connexion sécurisée de bout en bout
En résumé, un client ConnectMQ prêt pour la production se connecte sur le port 8883 (ou en WSS sur le 8084) avec la validation des certificats activée, s'authentifie avec des identifiants générés par le portail et un client ID de la forme YOUR_CLIENT_ID_<device>, publie sur des topics opaques à un rythme raisonnable, temporise en cas de 0x97 et de 0x89, et est supervisé via $SYS.
Pour un parcours côté appareil, consultez le tutoriel ESP32 MQTT, qui se termine par une version du sketch sécurisée par TLS.
Démarrer avec ConnectMQ
En tant que broker MQTT managé, ConnectMQ vous fournit d'emblée des endpoints TLS et WSS, des identifiants générés, la restriction des client IDs, l'isolation des tenants et la protection contre les abus : votre équipe peut se concentrer sur les aspects de la sécurité MQTT qui ne relèvent que d'elle. Créez un broker avec l'offre Serverless gratuite sur https://app.connectmq.com (sans carte bancaire) et connectez votre premier client sécurisé en quelques minutes.
Questions fréquentes
MQTT est-il sécurisé par défaut ?
Non. Le protocole MQTT définit des champs d'authentification, mais laisse le chiffrement et l'autorisation au broker et au transport. Il vous faut du TLS, des identifiants robustes par appareil et des limites raisonnables côté broker pour le sécuriser.
Quel port utiliser pour du MQTT sécurisé ?
Utilisez le port 8883 pour MQTT sur TLS et le port 8084 pour MQTT sur WebSocket sécurisé (WSS). Sur ConnectMQ, les deux utilisent un certificat Let's Encrypt reconnu publiquement.
Puis-je utiliser la zone publique de broker.connectmq.com en production ?
Non. La zone publique est anonyme et lisible par quiconque s'abonne à vos topics. Utilisez les identifiants du portail ConnectMQ pour toute donnée réelle ; les tenants authentifiés sont isolés de la zone publique et les uns des autres.
Que signifie le reason code 0x97 ?
0x97 est le reason code MQTT 5 qui signifie « Quota exceeded » (quota dépassé). ConnectMQ le renvoie lorsqu'un client dépasse une limite de son offre ou de sa zone ; votre client doit alors temporiser plutôt que réessayer immédiatement.
Peut-on désactiver la vérification des certificats pour tester ?
Uniquement sur une machine de développement jetable, et jamais dans un firmware livré ni dans du code de production. Désactiver la vérification supprime la protection contre les attaques de l'homme du milieu, qui est la principale raison d'utiliser TLS.



