loader

Kit cyber - Chapitre 10 : Calculatrice à distance

Premier chapitre du parcours injection de code du kit cyber

Nous mettons en place une petite calculatrice à distance : un client envoie un texte contenant une expression mathématique (par exemple « 2+2 » ou « 3*(4+5) ») et un dispositif serveur renvoie le résultat du calcul.
Ce système paraît très pratique : il suffit d’envoyer la formule souhaitée, et le serveur renvoie la réponse automatiquement par radio. C’est un exemple simple de service distant qui exécute des opérations demandées par un utilisateur.
Mais accepter et « exécuter » directement du texte envoyé par un tiers soulève des questions importantes. Même si, dans cette activité, les messages restent des expressions mathématiques inoffensives, il est utile de s’interroger dès maintenant sur ce que cela implique : notre programme traite automatiquement du contenu reçu de l’extérieur.

Dans notre calculatrice à distance, le serveur reçoit du texte contenant une opération, puis renvoie le résultat du calcul. Pour cela, il utilise une fonction spéciale appelée exec, qui exécute du code Python fourni sous forme de chaîne de caractères.
Par exemple, si le message reçu est la chaîne "2+3", et que l’on construit une instruction du type “resultat = ...” à partir du message reçu, exec va exécuter cette instruction et affecter à resultat la valeur 5. C’est très pratique : le serveur n’a pas besoin de connaître à l’avance le calcul à effectuer, il exécute simplement ce qui lui est envoyé.
Mais ce fonctionnement cache un danger : si le programme n’examine pas le contenu du message avant de l’exécuter, un utilisateur malintentionné pourrait envoyer du texte qui ne contient pas seulement une opération, mais aussi une commande imprévue, que le serveur exécuterait sans réfléchir. C’est ce qu’on appelle une injection : le fait d’introduire du code dans un système qui l’exécute sans contrôle. Ce problème ne touche pas seulement les calculatrices : on le retrouve aussi dans les sites web, les bases de données ou encore les applications connectées.

Le but de la carte client va simplement être d’envoyer une demande de calcul à la carte serveur (la calculatrice à distance), et, une fois le résultat reçu, d’afficher celui-ci sur la matrice de LED de la carte client.
On va définir deux types de messages :
  • CALCUL, envoyé par la carte client, qui prend comme contenu le calcul à effectuer, sous forme de chaîne de caractères
  • RESULTAT, envoyé par la carte serveur, qui prend comme contenu le résultat du calcul effectué


Le programme va donc devoir, au démarrage, envoyer un calcul à effectuer, puis écouter les messages reçus. Si, lorsqu’un message est reçu, sa clé (name) est RESULTAT, alors on récupère ce résultat et on l’affiche sur la matrice de LED.

Attention - Pour tous les programmes de ce parcours, il faut configurer la radio en utilisant le bloc associé, afin de définir la taille des messages à 64 ou plus. Dans le cas inverse, les programmes risquent de ne pas fonctionner.


Si tu es bloqué :
  • Vérifie qu’au démarrage la carte envoie bien un message dont la clé est CALCUL et la valeur est une chaîne de caractères contenant le calcul (par exemple "3*(2+7)").
  • Assure-toi que, dans la boucle, tu écoutes en continu les messages reçus et que tu ne traites que ceux dont la clé (name) est RESULTAT.
  • Pour t’aider à déboguer, tu peux d’abord faire afficher name et value dans la console avant d’afficher le résultat sur la matrice de LED.

La carte serveur, elle, va uniquement écouter les messages. Si elle reçoit un message avec la clé (name) CALCUL, va attribuer à une variable nommée resultat le calcul présent dans le message (value). Pour cela, on va utiliser le bloc permettant d’exécuter du code python à partir d’une chaîne de caractères :

Bloc exec

La chaîne de caractères envoyée par la carte client ne contient que le calcul à effectuer, il faut donc construire une chaîne qui permet de stocker le résultat de ce calcul dans la variable resultat. Voici comment faire :

bloc exec resultat

Il faudra aussi prendre en charge le fait que l’utilisateur peut envoyer une expression invalide. Dans une logique de robustesse (et de monkey testing, où l’on teste volontairement des entrées imprévues ou malformées), il faut éviter qu’un code invalide provoque une erreur qui fait “crasher” la carte. Il faut donc encapsuler le bloc d’exécution de code Python dans un bloc try/except, qui est lui capable de détecter les erreurs, et d’effectuer une action spéciale lorsque cela arrive. Dans notre cas, si le calcul reçu provoque une erreur, on renverra un message de type RESULTAT comportant le texte “erreur” :

bloc try/except


Enfin, il faudra renvoyer le résultat par radio, en utilisant un message de type RESULTAT.


Si tu es bloqué :
  • Vérifie que tu n’exécutes le bloc « exécuter le code Python » que lorsque la clé du message reçu est CALCUL.
  • Assure-toi que la chaîne passée à ce bloc est bien de la forme resultat = suivie du calcul reçu (sans guillemets autour du calcul).
  • Après le calcul, envoie un message de type RESULTAT dont la valeur est la variable resultat, et non le texte du calcul.

Téléverse les programmes sur les deux cartes micro:bit, en vérifiant qu’elles sont configurées sur le même canal et groupe radio. Redémarre les cartes : la carte client envoie automatiquement une expression à calculer, et la carte serveur renvoie le résultat. Observe la matrice de LED de la carte client : le résultat du calcul doit s’afficher.
Modifie ensuite l’expression de départ dans le programme de la carte client (par exemple 5+4, 3*(2+7), etc.) et vérifie que la carte serveur renvoie bien le bon résultat à chaque fois.

Dans cette activité, nous avons mis en place une calculatrice à distance : une carte joue le rôle de client en envoyant un calcul sous forme de texte, et une autre carte joue le rôle de serveur en exécutant ce calcul avec exec puis en renvoyant le résultat par radio. Cela nous a permis de découvrir comment des appareils peuvent communiquer entre eux, échanger des messages de type différent (CALCUL, RESULTAT) et automatiser un traitement sans intervention humaine.

Mais nous avons aussi vu que ce fonctionnement n’est pas sans risque : dès qu’un programme exécute directement du texte reçu de l’extérieur, il devient possible d’y injecter du code imprévu. C’est tout l’enjeu des attaques par injection, que l’on retrouve bien au-delà de notre simple calculatrice, dans les sites web, les bases de données ou d’autres services en ligne. La suite du parcours consistera à mieux comprendre ces attaques et à explorer des manières de limiter ce que l’on accepte et exécute, afin de concevoir des systèmes plus robustes et plus sûrs.

Pour aller plus loin :
  • Se renseigner sur la notion de service distant : de nombreux sites web et applications proposent des “API” qui effectuent des calculs ou des traitements à la demande, un peu comme notre calculatrice à distance.
  • Chercher les termes « exécution de code à distance » ou « remote code execution » pour comprendre pourquoi laisser un programme exécuter du texte reçu de l’extérieur pose des questions importantes de sécurité.

Licence d'utilisation

Licence Creative Commons

Cette ressource est mise à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 2.0 France