Sécurisez et protégez votre installation MQTT

Magazine
Marque
Hackable
Numéro
26
Mois de parution
septembre 2018
Domaines


Résumé

Je sais ce que vous vous dites. Vous avez installé votre broker et vos ESP8266 sur votre réseau local, il n'y a aucun besoin d'ajouter des mécanismes complexes pour éviter qu'un intrus ne joue avec votre système. N'est-ce pas ? Pourquoi donc alors fermez-vous votre maison à clé ? Personne ne peut entrer dans votre jardin, puisque le portail est fermé. Pourquoi ne pas laisser une paire de clés dans votre voiture ? Après tout, il faut déjà pouvoir y entrer pour démarrer...


Body

Faire reposer la sécurité de votre système sur la simple supposition que votre Wifi soit impénétrable est une mauvaise pratique et un risque qui ne vaut pas d'être encouru. Faisons les choses proprement, sécurisons tout cela, voulez-vous ?

L'installation MQTT que je viens de vous décrire est parfaite pour faire ses premiers pas dans le domaine et comprendre le fonctionnement général du système. Cependant, même pour une installation domestique, il est inacceptable de laisser ainsi n'importe qui ou n'importe quel montage pouvoir se connecter sans vérification aucune au réseau.

Bien entendu, le simple fait de mettre en place un point d'accès avec un niveau de sécurité acceptable (WPA2) est un premier pas vers la sécurisation du système mais, sans autres protections, ceci constitue également un point unique de défaillance. Il suffira à un voisin de craquer votre mot de passe WPA2 et le voisin est en mesure de faire plus ou moins ce qu'il veut avec votre installation MQTT. C'est un peu comme si vous décidiez que SSH est trop complexe et vous rabattiez sur un bon vieux Telnet, simplement parce qu'il n'est accessible qu'à la condition d'être connecté en Wifi. Je ne parle même pas ici de la situation où vous n'êtes pas le seul utilisateur du réseau et œuvrez dans un environnement professionnel où n'importe quel petit rigolo de passage peut à loisir jouer avec les données de vos capteurs ou vos ESP8266.

mqtt_ethernet

Une carte Arduino comme cette UNO équipée d'un shield Ethernet est parfaitement capable de dialoguer en MQTT. Malheureusement, l'utilisation de SSL/TLS n'est pas à sa portée et elle ne pourra donc plus être utilisée de cette façon.

1. Authentification

La première chose à faire pour ajouter une couche de sécurité à notre installation est de mettre en place une authentification. L'objectif est de forcer les clients MQTT à s'authentifier en prouvant leur identité avec un classique duo « identifiant » / « mot de passe ». Cette modification doit intervenir à la fois côté Mosquitto et côté croquis ESP8266. Le broker MQTT doit être en mesure de vérifier l'identité des clients et ceux-ci doivent la prouver.

Pour l'heure, nous n'avons pas touché à la configuration de Mosquitto se trouvant dans le fichier /etc/mosquitto/mosquitto.conf, contenant, par défaut, ceci :

pid_file /var/run/mosquitto.pid

persistence true

persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

Dans l'ordre, nous avons :

  • Le fichier contenant le numéro de processus du démon Mosquitto, permettant la gestion du fonctionnement en arrière-plan (mode serveur).
  • La directive permettant au serveur de conserver l'état des connexions, des abonnements et des messages dans un fichier enregistré sur le disque. Ceci permet au serveur de recharger ces informations en cas de redémarrage.
  • L'emplacement où doivent être stockées ces informations.
  • Le chemin complet vers le fichier contenant le journal d'activité du serveur.
  • Le répertoire contenant d'autres fichiers de configuration à prendre en compte.

Ce dernier point est celui qui nous intéresse, car nous n'aurons pas besoin de modifier le fichier mosquitto.conf directement. Il nous suffit de stocker les éléments de configuration supplémentaires dans ce répertoire sous la forme de fichiers. C'est exactement ce que nous allons faire pour ajouter l'authentification, mais avant cela nous devons créer un fichier de mots de passe.

mqtt_esp32

L'ESP8266 pourra être remplacé sans problème par une carte à base d'ESP32 qui, contrairement à une carte Arduino Ethernet, saura parfaitement gérer SSL/TLS. Je ne vois cependant pas l'intérêt d'utiliser toute cette puissance pour une simple sonde, à moins bien entendu que l'ESP32 ne soit chargé de traiter et d’afficher les données des topics auxquels il s'abonne...

Le paquet mosquitto met à notre disposition un outil sous la forme de la commande mosquitto_passwd, très similaire à la commande htpasswd permettant de créer un fichier similaire pour les services HTTP. Pour créer notre fichier de mots de passe, nous utiliserons :

$ sudo mosquitto_passwd -c /etc/mosquitto/passwd sondes

Password:

Reenter password:

L'option -c permet la création du fichier qui est précisé en argument (passwd dans /etc/mosquitto), juste avant l'identifiant à ajouter (ici sondes). L'outil vous demande ensuite de saisir deux fois de suite le mot de passe associé (vous ne voyez pas la saisie). Le fichier est alors créé et une ligne est ajoutée pour cet identifiant. Vous pouvez, en supprimant l'option -c, mettre à jour le mot de passe en spécifiant le même identifiant, ou ajouter une nouvelle entrée dans le fichier en en spécifiant un nouveau. Il vous est également possible d'utiliser l'option -D pour supprimer une entrée (ou tout simplement éditer le fichier pour supprimer la ligne correspondante). Attention, utiliser -c sur un fichier existant remplacera intégralement son contenu par l'unique nouvelle entrée.

Les mots de passe du fichier ne sont pas lisibles, car ceux-ci ne sont pas stockés, mais remplacés par un condensé (hash). En cas de problème de sécurité, il ne sera pas facile (mais toujours possible) de retrouver le mot de passe à partir du condensé. Ceci offre donc un minimum de sécurité qui ne devra pas vous empêcher de protéger l'accès au système sur la Pi (ne serait-ce qu'en changeant le mot de passe par défaut).

À présent que ce fichier est créé, nous pouvons modifier la configuration de Mosquitto afin de le prendre en compte. Pour cela, nous ajoutons un fichier, judicieusement nommé, dans /etc/mosquitto/conf.d. Appelons-le auth.conf :

password_file /etc/mosquitto/passwd

allow_anonymous false

password_file nous permet de spécifier le fichier à utiliser et allow_anonymous détermine si nous voulons ou non autoriser les connexions anonymes, et donc sans identifiant et mot de passe. Ici, nous refuserons toutes connexions non identifiées et authentifiées.

Nous n'avons plus qu'à enregistrer ce fichier et redémarrer le serveur :

$ sudo systemctl restart mosquitto.service

Dès cet instant, l'ESP8266 ne sera plus en mesure de se connecter au broker MQTT et nous devrons légèrement modifier notre croquis. Cette ajout d'authentification peut être rapidement fait puisqu'il nous suffit de changer une simple ligne : l'appel à la fonction client.connect() dans notre fonction reconnect(). Celle-ci passe de client.connect(readconf.myhostname) à client.connect(readconf.myhostname, “sondes”, “mot2passe”).

Après compilation et chargement dans l'ESP8266, nous pouvons tester l'ensemble comme précédemment avec les outils Mosquitto :

$ mosquitto_pub -h raspberrypiled.local \

-u "sondes" -P "mot2passe" -t ctrlled -m 1

$ mosquitto_sub -v -h raspberrypiled.local \

-u "sondes" -P "mot2passe" -t maison/+/valeur

maison/mqtttaf1/valeur hello world #15

maison/mqtttaf1/valeur hello world #16

Comme vous le voyez, l'option -u précise l'identifiant à utiliser et -P le mot de passe. Il ne sera désormais plus possible d'utiliser ces outils sans ces éléments, car le broker refusera la connexion en leur absence.

Il est également possible de pousser plus loin la précision de ce mécanisme d'authentification en mettant en place des ACL (Access Control List) n'autorisant la lecture ou l'écriture sur certains topics qu'en fonction de l'identifiant utilisé pour l'authentification ou encore l'identifiant client (clientid utilisé lors de la connexion). Ceci est très bien expliqué dans la page de manuel de Mosquitto (man mosquitto.conf), mais est un peu trop « poussé » pour le présent article, car réellement utile que pour un broker supportant énormément de projets.

2. Ce n'est pas suffisant : chiffrons !

L'authentification via un identifiant et un mot de passe est une bonne chose mais, même si celui-ci ne circule pas en clair (n'est pas lisible) lors d'un dialogue entre un client et le broker, le reste des informations échangées le sont. De plus, l'utilisation de condensés comme ceux utilisés ici pour les mots de passe peut également présenter un risque selon la méthode utilisée pour une éventuelle attaque (utilisation de rainbow tables).

S'il y a un risque que quelqu'un puisse intercepter le mot de passe chiffré et le décrypter d'une façon ou d'une autre, la méthode communément utilisée pour le gérer consiste à tout simplement chiffrer toute la communication. Ceci correspond exactement aux mêmes besoins et aux mêmes principes que ceux utilisés pour sécuriser les échanges entre un serveur web et un navigateur. Ça tombe bien, car la solution est exactement la même : TLS.

TLS, comme son prédécesseur SSL, permet de faire énormément de choses et peut vite devenir quelque chose de très complexe et difficile à gérer. Nous nous en tiendrons cependant ici à deux simples choses : chiffrer les communications pour les rendre inintelligibles pour une oreille indiscrète et nous assurer que les clients se connectent effectivement au bon broker et non une entité ayant usurpé son identité.

TLS utilise des certificats faisant office de carte d'identité exactement comme celle dans votre portefeuille. Ces certificats sont signés par une autorité de certification, seule légitimement en mesure de les délivrer. Avec une connexion à un site web, un certain nombre d'autorités de certification sont officiellement reconnues et un site disposera donc d'un certificat dont la signature pourra être vérifiée par le navigateur. De ce fait, non seulement la communication est chiffrée, mais le navigateur, en reposant sur la légitimité de l'autorité de certification, est assuré de l'identité du site qu'il visite. Le tenancier du site doit montrer patte blanche et prouver son statut de propriétaire à l'autorité de certification, qui délivrera, sous certaines conditions, un certificat.

tinyca

TinyCA est une application graphique permettant la gestion d'une petite autorité de certification, disponible sous GNU/Linux. Ceci peut être très intéressant pour gérer quelques dizaines de certificats, même s'il est parfaitement possible de s'en sortir avec l'outil openssl et un peu de rigueur et de méthode.

Dans le cas de notre installation MQTT, le principe est le même à une petite différence près : vous serez votre propre autorité de certification. En d'autres termes, vous jouerez deux rôles : celui qui délivre les certificats (autorité de certification) et celui qui demande un certificat, puis l'utilise (le broker Mosquitto). Les clients MQTT quant à eux se contenteront de vérifier le certificat du broker avant t'établir la connexion et l'utiliserons pour établir la liaison sécurisée.

Pour comprendre l'utilisation des certificats, il est possible d'imager cela à l'aide d'objets bien concrets du quotidien. L'autorité de certification dispose d'un tampon lui permettant de valider les demandes qu'elle reçoit. Les demandeurs, eux aussi, disposent de leur tampon afin de signer la demande. Le reste n'est qu'une affaire de formulaire à remplir et à tamponner. Voici le déroulé de la procédure :

  • L'autorité de certification étant ce qu'elle est et se suffisant à elle-même, commence par se fabriquer son tampon.
  • Elle crée ensuite un formulaire prouvant son identité, qu'elle tamponne elle-même. C'est un certificat auto-signé.
  • Le demandeur, notre broker, se fabrique également son tampon.
  • Il produit ensuite un formulaire de demande qu'il tamponne pour montrer qu'il vient bien de lui.
  • Le demandeur passe ensuite le formulaire à l'autorité de certification qui a pour tâche de vérifier l'identité du broker.
  • Comme tout est en règle, l'autorité de certification tamponne le formulaire qui devient alors un certificat en bon et due forme.

Pour vérifier un formulaire tamponné par l'autorité de certification, il n'est pas nécessaire de disposer du tampon de l'autorité de certification, une copie de son formulaire est suffisante. Pour utiliser le formulaire du broker en revanche, il faut posséder le formulaire signé et le tampon du broker, en plus du formulaire signé de l'autorité de certification. Si vous êtes le broker, vous avez votre tampon pour vérifier votre formulaire et le formulaire de l'autorité pour vérifier la signature.

Tout ceci, retranscrit en patois TLS, nous donne :

  • créer une clé pour l'autorité de certification ;
  • avec cette clé, créer un certificat auto-signé pour l’autorité de certification ;
  • créer une clé pour le broker ;
  • avec cette clé, créer une demande de certification ou CSR (Certificate Signing Request) ;
  • et enfin, signer la demande avec la clé de l’autorité de certification pour en faire un certificat valide.

Il faudra ensuite copier la clé de l'autorité de certification ailleurs et la supprimer de tout ce qui peut être accessible ou attaquable, car c'est littéralement et sans mauvais jeu de mots, la clé de voûte de tout le système. Si quelqu'un peut utiliser cette clé, il pourra produire des certificats comme bon lui semble et votre sécurité s'effondre. Notez au passage, tout de même, que les clés sont contenues dans des fichiers qui peuvent être chiffrés et protégés par un mot de passe. Mais vous avez compris l'esprit de la chose, ce n'est parce que le fichier est protégé par un mot de passe qu'on peut le laisser traîner un peu partout.

Cette énumération de 5 points résume ce que nous devons faire pour produire les éléments nécessaires pour faire fonctionner MQTT avec TLS et sécuriser correctement notre installation. Tout ce qu'il nous faut maintenant, c'est un outil pour faire cela. Il existe quelques applications graphiques permettant ces opérations (comme TinyCA sur Raspbian), mais lorsqu'il n'y a pas des dizaines de certificats à gérer, il est bien plus simple d'utiliser les outils par défaut d'OpenSSL.

On commence donc par générer la clé de l'autorité de certification :

$ openssl genrsa -aes256 -out ca.key 2048

Generating RSA private key, 2048 bit long modulus

..................+++

..........................................+++

e is 65537 (0x010001)

Enter pass phrase for ca.key:

Verifying - Enter pass phrase for ca.key:

openssl est un outil générique permettant de créer et manipuler tous les éléments nécessaires à l'utilisation de TLS. Il prend ainsi en argument une commande et des options qui peuvent être génériques ou spécifiques à la commande utilisée. Ici, nous générons une clé RSA (genrsa) de 2048 bits qui sera placée dans le fichier ca.key et protégée par un chiffrement AES256. Cette option, -aes256, est celle qui provoque la demande de mot de passe survenant après la génération. Dans la plupart des documentations, celle-ci est remplacée par -des3 pour un chiffrement triple-DES qui est encore suffisamment sûr selon le standard TLS, mais possède des vulnérabilités qui ne peuvent être ignorées. Mieux vaut donc se montrer prudent et opter pour quelque chose de plus sûr et moderne comme AES256, qui est le successeur de DES.

À présent que vous avez votre clé pour l'autorité de certification, nous pouvons produire un certificat auto-signé :

$ openssl req -new -x509 -days 3600 -key ca.key -out ca.crt

Enter pass phrase for ca.key:

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [AU]:FR

State or Province Name (full name) [Some-State]:Région

Locality Name (eg, city) []:Ville

Organization Name (eg, company) [Internet Widgits Pty Ltd]:Organisation

Organizational Unit Name (eg, section) []:Service

Common Name (e.g. server FQDN or YOUR name) []:Entité

Email Address []:adresse@mail.com

La commande req de openssl nous permet de produire une nouvelle (-new) demande (req = request = requête) de certificat, mais comme nous utilisons l'option -x509, celle-ci deviendra automatiquement un certificat signé de type « X.509 ». Nous précisons la clé à utiliser avec -key et le fichier à produire contenant le certificat avec -out. Notez enfin l'utilisation de -days permettant de spécifier la durée de validité du certificat en nombre de jours à partir de la date et l’heure actuelle. Ceci est indispensable.

Notez également l'aspect interactif de la génération, car openssl demande des informations concernant le sujet du certificat à produire (ou DN pour Distinguished Name) : un pays, un état/région, une ville, une organisation, un service dans l'organisation, un nom et une adresse mail. Ceci n'a pas grande importance dans le cas qui nous intéresse pour la production de ce certificat, mais essayez de rester cohérent tout de même, ces informations sont embarquées dans le certificat et potentiellement visibles.

Ces informations peuvent également être entrées sur la ligne de commandes via l'option -subj suivie d'une chaîne de caractères comme ”/C=FR/ST=Alsace/L=Colmar/O=Chez moi/OU=Service AC/CN=Mon AC”. Si vous devez produire plusieurs certificats, vous pouvez également choisir d'éditer le fichier /etc/ssl/openssl.cnf afin de préciser des valeurs par défaut de votre cru, qu'il vous suffira ensuite de valider quand openssl attendra les informations.

Nous avons à présent les deux fichiers propres à notre autorité de certification, ca.key et ca.crt, respectivement la clé et le certificat associé. Nous pouvons alors nous pencher sur le broker en commençant par générer une nouvelle clé :

$ openssl genrsa -out server.key 2048

Generating RSA private key, 2048 bit long modulus

.................................................

.................................................

....................+++

........+++

e is 65537 (0x010001)

Notez que nous n'avons pas précisé l'option -aes256 (ou -des3) et que la clé n'est donc pas chiffrée et protégée. Ceci est nécessaire, car le broker Mosquitto doit pouvoir démarrer ou redémarrer automatiquement. Avec une clé protégée par un mot de passe, ce démarrage serait bloqué par la demande de ce dernier.

Disposant maintenant d'une clé, nous pouvons produire une demande de certificat (ou CSR) :

$ openssl req -new -out server.csr -key server.key

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [AU]:FR

State or Province Name (full name) [Some-State]:Région

Locality Name (eg, city) []:Ville

Organization Name (eg, company) [Internet Widgits Pty Ltd]:Organisation

Organizational Unit Name (eg, section) []:Service

Common Name (e.g. server FQDN or YOUR name) []:raspibase.local

Email Address []:

Please enter the following 'extra' attributes

to be sent with your certificate request

A challenge password []:

An optional company name []:

Notez l'absence de l'option -x509. Nous créons une demande et non un certificat auto-signé. Point important ici, le Common Name ne peut être choisi arbitrairement, mais doit correspondre au nom de domaine utilisé pour contacter le serveur (typiquement le nom d'hôte de la Pi, plus « .local »). Ce nom, le FQDN pour Fully Qualified Domain Name (nom de domaine pleinement qualifié) est embarqué dans la demande et sera donc embarqué dans le certificat signé. C'est lui qui fait office de carte d'identité tamponnée pour le broker et permet d'établir la correspondance hôte/certificat. Les deux dernières lignes concernent des informations complémentaires que nous validons simplement sans rien spécifier.

Il est temps de créer ce pour quoi nous avons fait tous ces efforts, le certificat :

$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \

-CAcreateserial -out server.crt -days 1800

Signature ok

subject=C = FR, ST = Région, L = Ville, O = Organisation,

  OU = Service, CN = raspibase.local

Getting CA Private Key

Enter pass phrase for ca.key:

Cette opération consiste à prendre la demande produite pour le broker à partir de sa clé et de la signer avec la clé de l'autorité de certification. Il en résulte un nouveau fichier, server.crt qui, associé à la clé pourra entrer dans la configuration de Mosquitto. Notez que, comme pour le certificat de l'autorité de certification, nous avons ici une période de validité, qui rendra le certificat inutilisable après 1800 jours.

Il vous est possible d'obtenir les informations d'un certificat pour vérification, avec openssl :

$ openssl x509 -noout -fingerprint -sha1 -text -in /etc/mosquitto/server.crt

SHA1 Fingerprint=10:B3:81:C7:8A:21:81:66:EC:1C:8A:2C:D4:34:14:93:36:CE:39:19

Certificate:

    Data:

        Version: 1 (0x0)

        Serial Number:

            ee:7b:8b:19:c0:66:e5:9a

    Signature Algorithm: sha256WithRSAEncryption

        Issuer: C = FR, ST = Région, L = Ville, O = Organisation,

          OU = Service, CN = Entité

        Validity

            Not Before: Jul 24 16:09:36 2018 GMT

            Not After : Jun 28 16:09:36 2023 GMT

        Subject: C = FR, ST = Région, L = Ville, O = Organisation,

          OU = Service, CN = raspibase.local

        Subject Public Key Info:

            Public Key Algorithm: rsaEncryption

                Public-Key: (2048 bit)

[...]

Nous avons ici plusieurs éléments importants :

  • SHA1 Fingerprint est l'empreinte du certificat qui peut être vue comme un bref résumé de son contenu. Ceci nous servira dans le croquis pour les ESP8266 afin de nous assurer que le broker est celui qu'il prétend être.
  • Issuer est l'autorité de certification ayant produit le certificat.
  • Not Before et Not After bornent la période de validité du certificat, correspondant aux 1800 jours que nous avons spécifiés lors de la signature.
  • Subject résume les informations concernant l'identité embarquée dans le certificat. L'élément important est ici le CN (Common Name) qui doit correspondre au nom de domaine (FQDN) du broker.

Nous pouvons maintenant copier les trois fichiers, ca.crt, server.key et server.crt dans le répertoire de configuration de Mosquitto, /etc/mosquitto, puis mettre en sécurité la clé de l'autorité de certification (ca.key).

Nous nous tournons alors vers la configuration du broker et ajoutons un nouveau fichier dans /etc/mosquitto/conf.d, par exemple tls.conf, contenant :

port 8883

cafile /etc/mosquitto/ca.crt

keyfile /etc/mosquitto/server.key

certfile /etc/mosquitto/server.crt

tls_version tlsv1

Ici, après avoir changé le port sur lequel le broker est en attente, nous spécifions les différents fichiers et la version de TLS que nous souhaitons utiliser. Mosquitto fonctionne par défaut sur le port 1883, mais en cas d'utilisation de TLS, celui-ci devient, par convention, 8883. Une fois le service redémarré avec sudo systemctl restart mosquitto, à nouveau, notre ESP8266 n'est plus en mesure de se connecter au broker. Nous devons modifier notre croquis...

cert_finger

Les navigateurs web permettent d'obtenir facilement tout un lot d'informations intéressantes concernant les certificats utilisés par un site. On peut ici voir l'empreinte du certificat utilisé par Gmail affichée dans Chrome.

3. Adapter le croquis à l'utilisation de TLS

La modification du croquis permettant l'utilisation de TLS et donc le chiffrement des communications sera sensiblement plus conséquente que le simple ajout de l'authentification par mot de passe. Fort heureusement, le support ESP8266 pour Arduino sait parfaitement prendre en charge SSL/TLS et ceci sera presque transparent pour nous. Tout ce que nous avons à faire est de procéder à quelques vérifications avant de nous connecter.

Les communications via TLS (ou plus exactement au-dessus de TLS) dans le cas d'un broker MQTT se font non plus sur le port 1883, mais sur 8883. Ce sera donc là le premier changement dans notre croquis en passant de :

#define MQTT_PORT 1883

à

#define MQTT_PORT 8883

Nous devrons également changer le type d'objet utilisé pour représenter la connexion au serveur de :

WiFiClient espClient;

en

WiFiClientSecure espClient;

Et, puisque nous nous occupons du début du croquis, nous en profitons pour définir une macro destinée à simplifier l'utilisation du fingerprint du certificat du broker. Cette empreinte peut être obtenue à distance avec la commande openssl s_client -connect raspibase.local:8883 | openssl x509 -noout -fingerprint, ou mieux, localement sur la Pi avec openssl x509 -noout -in /etc/mosquitto/server.crt -fingerprint. La chaîne de caractères obtenue sera alors tout simplement copiée/collée dans le croquis.

#define FINGERPRINT "10:B3:81:C7:8A:21:81:66:EC:1C:8A:2C:D4:34:14:93:36:CE:39:19"

Notez qu'en temps normal, avec des configurations matérielles plus conséquentes, comme un navigateur sur un PC ou un smartphone, la vérification est plus poussée puisqu'on récupère le certificat du serveur et qu'on en vérifie la signature en utilisant le certificat de l'autorité de certification stockée localement. Dans le cas de l'ESP8266, ceci représenterait cependant une charge de travail non négligeable et une consommation importante de ressources (mémoire). Pour obtenir un résultat approchant, nous partons du principe que le certificat a été vérifié par d'autres moyens (avec openssl par exemple) et que, si le fingerprint est bien celui du certificat attendu, alors nous dialoguons avec le bon serveur.

letsencrypt

Être sa propre autorité de certification est quelque chose de viable dès lors qu'on ne travaille pas « publiquement ». Pour tout ce qui est connecté à Internet en revanche, il faudra faire appel à une autorité reconnue. Celle créée par la Linux Foundation dans le but de promouvoir l'utilisation du chiffrement et de SSL/TLS est gratuite, ouverte, automatisée et très populaire.

Le décor étant en place, nous pouvons maintenant réviser la seule fonction impactée par le passage à TLS :

void reconnect() {

  // Connecté au broker ?

  while(!client.connected()) {

    // non. On se connecte.

    // connexion via "espClient" et non "client"

    if(!espClient.connect(mqtt_server, MQTT_PORT)) {

      Serial.println("Unable to TLS connect");

      delay(5000);

      continue;

    }

    // vérification du fingerprint du broker

    if(!espClient.verify(FINGERPRINT, mqtt_server)) {

      Serial.println("Fingerprint check failed");

      espClient.stop();

      delay(5000);

      continue;

    }

    // déconnexion

    espClient.stop();

    // connexion MQTT via PubSubClient

    if(!client.connect(readconf.myhostname, "sondes", "mot2passe")) {

      Serial.print("Erreur connexion MQTT, rc=");

      Serial.println(client.state());

      delay(5000);

      continue;

    }

    Serial.println("Connexion serveur MQTT ok");

    // connecté.

    // on s'abonne au topic "ctrlled"

    client.subscribe("ctrlled");

  }

}

Deux conditions if viennent s'ajouter à notre fonction. La première permet de tester le résultat d'une tentative de connexion au broker, mais directement via l'objet espClient et non celui représentant la connexion MQTT. Nous nous connectons simplement au serveur pour récupérer les informations de son certificat. Si cette connexion réussie, nous pouvons alors utiliser la méthode verify() afin de comparer les fingerprints. Ce n'est que si cette vérification réussit que nous mettons fin à la connexion pour nous reconnecter en utilisant, cette fois, l'objet client utilisé par la bibliothèque PubSubClient.

MQTT Dash Android-s

MQTT Dash est une application Android permettant de se connecter à un broker MQTT. C'est parfait pour avoir une vision des informations et publier sur vos topics. Et en plus, l'application supporte aussi bien l'authentification et SSL/TLS.

Une fois le croquis recompilé et chargé dans l'ESP8266, vous devez constater exactement le même comportement qu'avant le passage à TLS. Côté Pi en revanche, nous devrons également modifier les lignes de commandes utilisées pour nous connecter au broker en précisant le nouveau port à utiliser ainsi que les éléments permettant l'utilisation de TLS :

$ mosquitto_pub -h raspberrypiled.local -p 8883 \

--tls-version tlsv1 --cafile /etc/mosquitto/ca.crt \

-u "sondes" -P "mot2passe" -t ctrlled -m 0

$ mosquitto_sub -v -h raspberrypiled.local -p 8883 \

--tls-version tlsv1 --cafile /etc/mosquitto/ca.crt \

-u "sondes" -P "mot2passe" -t maison/+/valeur

maison/mqtttaf1/valeur hello world #15

maison/mqtttaf1/valeur hello world #16

[...]

Ici, contrairement à la simplification mise en œuvre avec l'ESP8266, mosquitto_pub et mosquitto_sub vont procéder classiquement, en vérifiant la signature sur le certificat proposé par le serveur et s'assurant ainsi qu'il a bien été émis par notre autorité de certification.

Pour finir

Ceci peut paraître être beaucoup de travail pour quelque chose qui peut ne sembler que vaguement important. Pourtant, la sécurité n'est pas quelque chose qu'il faut prendre à la légère et simplement faire reposer sur une idée reçue consistant à dire « si je ne travaille que sur un réseau local, il n'y aura pas de problème ». Non seulement ceci est justement la cause de bien des maux, mais « penser sécurité » localement est aussi une façon de vous faciliter le passage à une autre échelle.

L'utilisation de TLS et des certificats dès la construction de la base de votre projet vous permettra de transposer facilement celui-ci directement sur Internet et donc d'installer, par exemple, votre broker (ou un second broker) sur un serveur accessible globalement, depuis n'importe où. Pour rendre tout cela encore plus universellement utilisable, vous pourrez également avoir recours aux services gratuits d'une autorité de certification ouverte comme Let's Encrypt et donc utiliser des certificats signés par une autorité reconnue.

En ce qui me concerne, il n'est pas davantage question d'utiliser MQTT sans chiffrement que d'utiliser, par exemple, Telnet en lieu et place de SSH sur un réseau local et ce, même si l'ensemble Pi+ESP8266s forme un réseau wifi distinct. C'est bien plus qu'une question de principe, c'est une affaire de bonnes pratiques et d'habitudes.

Remarquez cependant ici que la sécurité est loin d'être optimale. Dans l'absolu, rien n'empêche un attaquant d'observer la première connexion au broker puis d'usurper son identité pour la seconde connexion. Bien sûr, il est possible de vérifier le fingerprint après la connexion via PubSubClient puisque espClient est utilisé par client.connect() mais, dans ce cas, la tentative d'authentification a déjà été faite. Ceci ne peut malheureusement pas être solutionné sans modifier la bibliothèque.

Malgré ce point gênant, ceci forme une base solide pour l'utilisation de MQTT pour bon nombre de projets et a été l'occasion pour moi, et je l'espère pour vous, de faire connaissance avec ce protocole qui est, de toute évidence, parfaitement adapté pour bon nombre de réalisations, du contrôle de dispositifs en passant par le déploiement de capteurs.



Articles qui pourraient vous intéresser...

Les taxonomies se cachent pour ne pas mourir

Magazine
Marque
MISC
Numéro
113
Mois de parution
janvier 2021
Domaines
Résumé

« Attention, nouveau virus ! » Nombreux sont les articles à nous alerter régulièrement, par cette métonymie, sur l’émergence d’un nouveau malware. Pourtant, le terme de virus a-t-il encore un sens aujourd’hui ? Wannacry était-il un ver, ou un ransomware ? NotPetya, un wiper, ou bien un ver ? Et plus encore, au-delà de l’utilisation de termes et expressions se pose la question de la nécessaire catégorisation des incidents de cybersécurité ; pourquoi, comment, à quelles fins ? Essai (critique) de réponse.

Les difficultés du désassemblage sur ARM

Magazine
Marque
MISC
Numéro
113
Mois de parution
janvier 2021
Domaines
Résumé

Cet article aborde les problèmes spécifiques à l’architecture ARM qui se posent lorsqu’on désassemble un exécutable, c’est-à-dire lorsqu’on l’analyse statiquement pour en produire une représentation en langage assembleur. En effet, les particularités de l’architecture ARM peuvent rendre le désassemblage – déjà habituellement compliqué – particulièrement ardu.

Contrôle de ventilation PC par Arduino

Magazine
Marque
Hackable
Numéro
36
Mois de parution
janvier 2021
Domaines
Résumé

Les configurations PC actuelles reposent autour de processeurs (CPU comme GPU) qui sont certes très puissants en termes de calcul, mais également très consommateurs en énergie. Or la quasi-totalité de cette énergie électrique sera finalement transformée en chaleur que la machine doit dissiper, souvent activement. Rien d'étonnant donc de voir dans ces ordinateurs des systèmes de refroidissement normalisés qui pourront être utilisés par ailleurs, à condition d'être judicieusement contrôlés...

Sûreté mémoire : le temps des cerises

Magazine
Marque
MISC
Numéro
113
Mois de parution
janvier 2021
Domaines
Résumé

L’étude et la compréhension des buffer overflow datent de 1972, et leurs premiers usages documentés de 1988 [1]. Près de 50 ans plus tard, où en sommes-nous ? Il nous faut bien admettre que la situation est déprimante : Microsoft et Google reconnaissent chacun ([2], [3]) que près de 2/3 des attaques utilisent à un moment ou un autre une vulnérabilité mémoire. Le ver Morris, qui n’était au départ qu’une preuve de concept, avait quand même coûté la bagatelle de quelques millions de dollars à l’époque… Aujourd’hui, les coûts sont abyssaux : sur le plan financier bien sûr, mais aussi pour nos vies privées, voire nos vies tout court. Face à ce problème, de nombreuses approches sont possibles : analyse statique du code, instrumentation et vérification à l’exécution, langages « sûrs »… Je vous propose d’explorer dans cet article un vieux concept remis au goût du jour, les capabilities, et tout ce qu’elles pourraient nous permettre de faire.