1. Preface

Ce document présente un retour d’expérience d’une introduction à la cybersécurité, d’après le bloc 3 du référentiel du BTS SIO SLAM.

Dans le cadre de leur formation (troisième semestre), les étudiants ont eu la charge de réaliser une application web, en mode projet. Outre le fait que leur projet devait être livré à une date donnée (sur un dépôt git distant de leur choix), associé à un rapport détaillé (README du projet), nous attendions qu’il intègre des scénarios d’actions mal intentionnées et la mise en oeuvre de contre mesures de défense.

Les exemples de Evil User Stories ([EvilUS]) présentés ici, sont tirés de travaux de ces étudiants (deuxième année du BTS SLAM, lycée Léonard de Vinci de Melun, 2021-2022). Ces exemples sont donc centrés sur des problèmes liés aux cas d’utilisation métier de ce projet.

Pour ceux qui souhaitent reconduire cette expérience très exactement, voici le lien vers le projet : https://ocapuozzo.github.io/mission-etl-csv/ (libre utilisation). Compter minimum 3 semaines de travail étudiant, couvrant toutes les plages de TP info, plus un temps certain de travail à domicile (première semaine des vacances de Toussaint, par exemple)

2. Résumé

La cybersécurité en développement logiciel (défense) nécessite un esprit d’analyse certain qui s’appuie en partie sur une connaissance fine des technologies mises en oeuvre (infrastructures, protocoles, architectures des tiers, architectures en couches…​). Cette connaissance se forge par l’expérience.

Enseigner la cybersécurité à BAC+2, à des débutants, c’est accompagner l'étudiant sur le chemin de l’expérience et en même temps l'éclairer à la fois sur les bonnes pratiques et les usages déviants.

Pour autant, l'étudiant a tendance à se focaliser principalement sur la consolidation de connaissances techniques nouvelles (comprendre la technologie, mettre au point l’application) laissant une moindre place à l'étude de bonnes pratiques et des usages mal intentionnés. Normal, car ces études ont comme prérequis une bonne dose d’expérience…​

expérience prime
l’expérience prime

L'étude des risques cyber, tout comme celle des tests unitaires, est discriminante dans la mesure où elle induit un travail et un recul sur un réel construit et opérationnel (l’application).

L’accès à ce type de formation est ainsi clairement monté en exigence, et va dans le sens des attendus de professionnels du secteur. (https://www.lemonde.fr/blog/binaire/2015/11/05/la-culture-de-la-cybersecurite/).

À nous, enseignants, de relever le défi de sensibiliser l’ensemble de nos étudiants aux risques liés à la cybersécurité, et aux actions pour en minimiser l’impact.

Conclusion

L’ANSII préconise d’intégrer les risques cyber dès le début d’un projet. C’est ce que nous avons tenté de faire, en intégrant la recherche, par l'étudiant, de scénarios d’usages malveillants et de contre-mesures dès la conception des premières briques de leur application.

Cette pratique s’avère payante car elle sensibilise l'étudiant à la fois aux risques en cybersécurité et à sa part de responsabilité dans ce domaine. Nous avons décidé de la généraliser sur l’ensemble des projets menés par les étudiants.

3. Une sélection d’Evil User Stories proposés par les étudiants

3.1. Team : Le nain et l'échelle

Evil User Story 1

En tant que personne malveillante, je souhaite obtenir les données de connexion à la base de données utilisée par l’application Vetux-Line, en vue d’exploiter des données d’autres bases de données hébergées sur le même serveur que Vetux-Line.

Contre-mesure : En tant que développeur, je vais créer un identifiant de base de données spécialement pour la base de données de Vetux-Line pour empêcher un utilisateur malveillant d’accéder à d’autres bases de données sur le même serveur. Pour cela avec phpMyAdmin je crée ce nouvel utilisateur comme ceci:

phpmyadmin create user.png

Et dans le fichier .env je précise les informations de connexion à la base de données avec cette ligne:

    DATABASE_URL="mysql://vetux_line:wNgEf23m*7MZdWZ9@127.0.0.1:3306/vetux_line?serverVersion=mariadb-10.4.21"
Mise en garde de l’enseignant

L’utilisation de solutions d’administration de base de données par l’intermédiaire d’un tiers applicatif comme phpmyadmin est à éviter si possible, car cette pratique va à l’encontre du principe de réduction de la surface d’attaque.

Préférez une console d’administration, connexion en SSH, directement sur le serveur de production, utilisant des solutions CLI.

Evil User Story 2

En tant que personne malveillante, je cherche à accéder à certaines pages sans authentification, dans le but d’avoir accès aux actions et aux données permises à certains rôles seulement.

Concept de contre-mesure : [moindre-privilege]

Contre-mesure: En tant que développeur, je veux restreindre l’accès à certaines pages à des utilisateurs ayant un rôle spécifique, afin d'éviter qu’un utilisateur malveillant ait accès aux actions et données de ces rôles. Pour cela je configure dans le fichier security.yaml les lignes de acces_control:

access_control:
   - { path: ^/utilisateur, roles: ROLE_GESTIONNAIRE }
   - { path: ^/utilisateur/admin, roles: ROLE_ADMIN }
   - { path: ^/home, roles: ROLE_GESTIONNAIRE }

Ainsi, toutes les routes commençant par /utilisateur/admin seront uniquemant accessibles par les utilisateurs avec le rôle ROLE_ADMIN et de même pour les routes commençant par /home pour les utilisateurs avec le rôle ROLE_GESTIONNAIRE.

Dans les contrôleurs de l’application, je définie un préfixe de route pour toutes ses méthodes contrôleur. Par exemple dans UtilisateurController.php j’utilise une annotation pour définir la racine de route utilisateur, propre à cette classe et valable pour toutes ses méthodes contrôleur :

#[Route('/utilisateur')]
class UtilisateurController extends AbstractController

Ainsi les méthodes contrôleur de cette classe ayant une route commençant par /admin, ne seront accessibles qu’aux utilisateurs ayant le rôle ROLE_ADMIN.

La classe UploadController.php aura /home comme préfixe de route.

#[Route('/home')]
class UploadController extends AbstractController

Ainsi, toutes ses méthodes contrôleur seront accessibles qu’aux seuls utilisateurs ayant le ROLE_GESTIONNAIRE.

Evil User Story 3

En tant que personne malveillante, je veux uploader des fichiers pour faire planter le serveur ou le hacker.

Concepts de contre-mesure : ne pas diffuser de données techniques d’erreur, ne jamais faire confiance aux données d’entrée.

Contre-mesure : En tant que développeur, je veux seulement autoriser les fichiers csv dans l’upload pour éviter des attaques malveillantes. Pour cela j’interviens dans la classe contrôleur UploadController.php afin de vérifier le type de chaque fichier reçu :

 foreach ($files as $file)  {
   $filetype = $file->getMimeType();
   if (str_contains($filetype, '/csv')){
     $filename = $file->getClientOriginalName();
     $uploader->moveTo($uploadDir, $file, $filename);
   } else {
     return $this->render('home/index.html.twig');
   }
 }

getMimeType() renvoie le type de fichier avec son extension sous forme: type/extension.

Ici on vérifie juste si dans cette réception on a bien l’extension csv via un appel à str_contains et si oui on récupère le nom du fichier et on le traite (avec notre objet service référencé par $uploader), sinon on renvoie à la page d’upload.

Nos fichiers csv ont comme MimeType application/csv et pas text/csv, on a donc dû vérifier seulement la présence de l’extension.

Remarque enseignant

Attention, solution naïve, l’habit ne fait pas le moine !

L’extension informe sur le contenu d’un fichier mais ne le garantit pas. Constatez-le par vous-même : Le changement d’extension du nom d’un fichier est sans impact sur son contenu.

D’autre part, la limite de la taille maximale des fichiers autorisés est également à considérer. Généralement sous la forme d’un paramètre du service HTTP en amont.

3.2. Team : Les Pas d’ID

Evil User Story 4

En tant qu’utilisateur malveillant je veux empecher l’accès au site en faisant une attaque par déni de service ([DDos]) pour réduire la productivité du service en question.

Concept de contre-mesure : Menaces [DDoS] à intégrer dans le plan de mise en production.

Contre-mesure : En tant que développeur pour empêcher les attaques dos je m’assure que l’application n’utilise pas de composants sujets à de telles attaques et je me sers des protections mises a disposition par les hébergeurs (mécanisme de filtrage en bordure de réseau par exemple)

Exemple hébergeur OVH (présenté par l’enseignant)

Ci-dessous, des extraits de courrier envoyé par OVH à un de ses clients suite à la détectection une attaque [DDoS].

Message de l’hébergeur OVH ayant détecté une attaque DDoS
Madame, Monsieur,

Nous venons de détecter une attaque sur l'adresse IP x.x.x.x.

Afin de protéger votre infrastructure, nous avons aspiré votre
traffic sur notre infrastructure de mitigation.

Toute l'attaque sera ainsi filtrée par notre infrastructure, et seul
le traffic légitime arrivera jusqu'à vos serveurs.

A la fin de l'attaque, votre infrastructure sera immédiatement retirée de la mitigation.

Puis, quelque temps plus tard :

Message de l’hébergeur OVH ayant détecté la fin de l’attaque
Madame, Monsieur,

Nous ne détectons actuellement plus d'attaque sur l'adresse IP x.x.x.x.

Votre infrastructure est maintenant retirée de notre mitigation.

Pour plus d'informations sur l'infrastructure de mitigation OVH : https://www.ovh.com/fr/anti-ddos/

Cordialement,

Votre Service client OVHcloud

3.3. Team : Yannick

Evil User Story 5

En tant que personne malveillante, je veux utiliser la barre d’adresse afin d’avoir accès aux différentes routes de l’application Vetux-line sans avoir besoin de me connecter.

Concept de contre-mesure : [moindre-privilege]

Contre-mesure : En tant que développeur, afin d’empêcher les personnes malveillantes qui souhaitent, à partir de la barre d’adresse, accéder aux différentes routes de l’application Vetux-Line sans être connecté.

Les méthodes contrôleur de la classe IndexController sont annotées par @IsGranted("ROLE_ADMIN"). Cette annotation permet de restreindre l’accès à tous les utilisateurs qui ne sont pas connecté ou qui ne possède pas le rôle ROLE_ADMIN aux différentes routes du controller. La personne malveillante, en essayant de se connecter à la route admin/fusion par exemple, ne va pas pouvoir y accéder, car elle sera directement redirigée sur la page de connexion.

Vidéo de démonstration : https://youtu.be/DO1L1NVX6XI

Ramarque

Avec symfony la gestion des habilitations peut être réalisée :

  • Par configuration (security.yaml)

  • Par annotations (de niveau classe ou méthode)

  • Par instructions dans le corps des méthodes

3.4. Team : Schoolalexis

Evil User Story 6

En tant que personne malveillante, je veux avoir accès aux données de connexion à la base de données afin d’exploiter les mots de passes et autres données.

Concept de contre-mesure : [reduction-de-la-surface-d-attaque]

Contre-mesure : En tant que développeur, afin d’empêcher des personnes malveillantes qui souhaitent, à partir de la base de données, se connecter aux comptes des utilisateurs et exploiter leurs mots de passe (dans le cas de l’application Vetux Line), je sécurise le fichier .env qui contient l’identifiant de connexion à la base de données.

Pour cela, je n’inscris pas de données sensibles dans .env (données de production), et je crée un fichier .env.local pour y placer des données en lien avec l’environnement de test (machine du dev par exemple). Je m’assure que ce fichier n’est pas pris en compte dans le logiciel de versionnage Git, pour ne pas être sauvegardé sur un serveur distant.

Exemple :

gitignore
#  symfony/framework-bundle #
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
#  symfony/framework-bundle #

Dans .env j’inscris :

DATABASE_URL="mysql://<user>:<password>@127.0.0.1:3306/<database>?serverVersion=<version>"

À charge de la personne responsable de la mise en production de renseigner les données de connexion à la base de données dans le fichier de configuration .env.

Remarque enseignant

Une autre solution consiste à chiffrer les variables d’environnement.

Instead of defining a real environment variable or adding it to a .env file, if the value of a variable is sensitive (e.g. an API key or a database password), you can encrypt the value using the secrets management system.

— https://symfony.com/doc/current/configuration.html#configuration-based-on-environment-variables
Symfony

3.5. Team : Les Alternants

Evil User Story 7

En tant que personne malveillante j’ai découvert que Vetux-Line utilise une ancienne version de Symfony qui n’est pas à jour. Je vais donc me documenter sur les failles de cette ancienne version, en vue de les exploiter.

Concept de contre-mesure : [maintien-en-conditions-de-securite]

Contre-mesure : En tant que développeur je surveille les mises à jour de Symfony, particulièrement en terme de sécurité (site https://symfony.com/), ainsi que les autres composants tiers utilisés par mon projet. Exemple de commandes :

symfony self:update

puis

composer update

Je réalise cette commande supplémentaire pour vérifier qu’il n’y a pas d’autres failles de sécurité en exécutant cette commande :

symfony security:check

Pour vérifier que les composants dont dépend l’application n’ont pas de failles détectées à ce jour. Si nécessaire je mets à jour la version des composants en prenant soin de bien consulter les recommandations de mises à niveau et de tester l’application (tests de non régression)

Evil User Story 8

En tant que personne malveillante si j’arrive à extraire les données des utilisateurs de l’application, je compte utiliser leur identité et leur mot de passe pour accèder à d’autres applications.

Concept de contre-mesure : [reduction-de-la-surface-d-attaque]

Justification: En effet, plusieurs études (https://www.cyclonis.com/fr/rapport-83-pour-cent-utilisateurs-interroges-utilisent-meme-mot-de-passe-plusieurs-sites/ ou https://www.zdnet.fr/actualites/mot-de-passe-1-personne-sur-7-n-en-utilise-qu-un-seul-partout-39829024.htm et bien d’autres..) démontrent que les personnes utilisent souvent le même mot de passe un peu partout.

Contre-mesure : En tant que développeur, si jamais une grosse fuite de données se produit, je sécurise la base de données en chiffrant tous les mots de passe pour éviter de réutiliser les mots de passe des utilisateurs.

J’ai donc haché le mot de passe des utilisateurs par l’intermédiaire du module de sécurité de Symfony, en particulier :

use
Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

[...]

3.6. Team : Tournesol

Evil User Story 9

En tant qu’utilisateur malveillant si j’arrive à accèder à des données d’autres utilisatueurs de même privilège, je peux alors aspirer leurs données en vue d’exploitations illégales, ou pire, endommager les données pour discréditer le service.

Exemple connu Optical Center avril 2019 (utilisateur sans privilège !) : Une délégation de la CNIL a effectué des vérifications en ligne qui ont permis de constater qu’il était possible d’accéder librement, à partir des « URL » qui lui avaient été transmises, à des factures contenant les données à caractère personnel suivantes: le nom, le prénom, l’adresse postale, la correction ophtalmologique et, pour certaines d’entre elles, la date de naissance des clients ainsi que leur numéro d’inscription au répertoire national d’identification des personnes physiques (NIR). La délégation a également constaté qu’il était possible, depuis le domaine « optical-center.fr » et sans authentification préalable dans l’espace client, d’exporter au format « CSV », un échantillon de 2085 fichiers correspondant, après suppression des doublons, aux données de 1207 clients et faisant notamment apparaître 158 NIR. La société Optical Center a eu une amende de 250 000 euros (source : https://www.cnil.fr/sites/default/files/atoms/files/decision-n-422575.pdf)

Contre-mesure : En tant que développeur, je m’assure que les utilisateurs de même privilège n’accèdent pas aux fonctionnalités leur permettant d’agir sur les données personnelles d’autes utilisateurs de même privilège.

Exemple de trou de sécurité
 /**
  * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_GESTIONNAIRE')")
  *
  * @Route("/{id}/edit", name="utilisateur_edit", methods={"GET","POST"})
  */
  public function edit(Request $request, Utilisateur $utilisateur,
                       UserPasswordHasherInterface $passwordHasher): Response
  {

   // code sous garde de sécurité qui manque de "robustesse"

   [...]

  }

Une solution consiste à affiner, dans le corps de la méthode, l’habilitation de l’utilisateur à solliciter ce service.

Exemple d’une correction possible
 /**
  * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_GESTIONNAIRE')")
  *
  * @Route("/{id}/edit", name="utilisateur_edit", methods={"GET","POST"})
  */
  public function edit(Request $request, Utilisateur $utilisateur,
                       UserPasswordHasherInterface $passwordHasher,
                       LoggerInterface $logger): Response
  {
    $isAdmin = $this->isGranted('ROLE_ADMIN');(1)
    if (($this->getUser()->getUserIdentifier() !== $utilisateur->getUserIdentifier())
      && !$isAdmin)  { (2)
      // un utilisateur ne peut pas modifier/consulter les données
      // d'un autre, sauf s'il est ADMIN
      $logger->info('This user '. $this->getUser()->getUserIdentifier()   (3)
        . ' hack attempt edit user id : ' . $utilisateur->->getUserIdentifier());
      $this->addFlash("message", "Vous ne pouvez pas modifier cet utilisateur"); (4)
      return $this->redirectToRoute('membre'); (5)
    }
    [...]
1 Vérifier si l’utilisateur courant est un administrateur
2 Seuls l’utilisateur concerné ou les administrateurs sont elligibles ici
3 journalise cette action non autorisée (TODO vérifier sa temporalisation)
4 Est-il opportun de présenter un message à cet utilisateur ?
5 Retourne un ordre de redirection, car cette requête n’a pas lieu d'être.
Journalisation

On remarquera l’instruction de journalisation (logger) de l’action malveillante.

Très utile pour analyser des attaques silencieuses.

La généralisation de journalisation de toutes actions illégales est à envisager ([zero-trust])

4. Conclusion

Cette première expérimentation (première année d’examen du nouveau référentiel SIO) a permis de mesurer la difficulté à enseigner les principes de cybersécurité à des débutants en programmation. Les propositions d'étudiants présentées ici ont, en partie, été reformulées, mais restent relativement fidèles à leur version originale.

Seule la proposition de la team Tournesol n’est pas une proposition d'étudiant (Evil User Story n°9, gestion des données du profil utilisateur contrôlée uniquement sur le rôle de l’utilisateur). Malgré le fait que le cas Optical Center ait été évoqué en cours, la faiblesse du code généré par le module maker d’authentification dans sa version d’octobre 2021 n’a pas fait l’objet d’une contre-mesure. Nous pensons que cette proposition n’a pas été retenue par les étudiants de par sa relative complexité, qui nécessite un temps de recul basé sur une expérience en devenir.

4.1. Qualité de l’expérience

Il existe de la part de l'étudiant une tendance certaine à rechercher systématiquement une solution à tout problème sur internet. Normal, car on leur a toujours dit que l’on trouve (de) tout sur internet :)), rendant difficile, pour l’apprenant, de distinguer ce qui est du ressort d’une solution logique à construire - avec les moyens sous la main - d’une recherche d’une solution toute faite.

Par exemple le projet demande une fusion sélective très particulière de deux fichiers CSV, et quelques étudiants ne se sont pas contentés d’un exemple de code de lecture/écriture d’un tel fichier, cherchant durant de longs moments une solution de fusion clé en main sur le net…​

Dans la même veine, suivre un tutoriel n’est pas de l’expérience, mais aller au delà, c’est à dire comprendre ce qui a été réalisé, l'adapter à un projet, l'étendre sur la base d’une idée d’amélioration ou créer de nouvelles fonctionnalités, oui. L’expérience forge la créativité et inversement.

La recheche par l'étudiant de scénarios d’usages déviants, et leur contre-mesure, participe au développement de sa créativité. C’est une dimension que nous, professeurs, avons décidé de prendre en compte dans les évaluations.

Enfin, signalons qu’un tiers environ de nos étudiants n’a pas été en mesure de réaliser le travail demandé. Leur capacité à transposer des savoir faire, leur niveau d’implication, n’ont pas été suffisants pour atteindre les objectifs fixés.

Test

5. Glossaire

Evil User Story

Récit d’un utilisateur (User Story) mal intentionné, connu aussi sous le nom abuser story.

Deni de service

Une attaque par déni de service vise à rendre indisponible un ou plusieurs services par surcharge de la bande passante ou épuisement des ressources système. "Certaines attaques visent à épuiser les capacités de traitement d’une cible. Par exemple, un attaquant peut chercher à atteindre la limite du nombre de connexions concurrentes qu’un serveur web peut traiter. Dans ce cas, l’attaquant envoie en permanence un grand nombre de requêtes HTTP GET ou POST au serveur ciblé. Il est également possible d’envoyer des requêtes partielles, puis de transmettre la suite de ces requêtes à intervalles réguliers, dans le but de maintenir les connexions ouvertes le plus longtemps possible et d’éviter la fermeture des connexions au-delà d’un délai fixé. D’autres types d’attaques applicatives cherchent à épuiser les ressources de calcul d’un serveur en initiant un grand nombre de sessions TLS, ou encore à tirer parti de faiblesses dans la conception d’une application web" Source : https://www.ssi.gouv.fr/uploads/2015/03/NP_Guide_DDoS.pdf

Ligne de commande

Une interface en ligne de commande (en anglais command line interface, couramment abrégé CLI) est une interface homme-machine dans laquelle la communication entre l’utilisateur et l’ordinateur s’effectue en mode texte. source : https://fr.wikipedia.org/wiki/Interface_en_ligne_de_commande

Mitigation

La mitigation concerne les moyens et mesures mis en place pour atténuer les effets négatifs sur un serveur ou un service liés aux attaques DDoS. La mitigation consiste à filtrer le flux pour ne laisser passer que le trafic légitime. source : https://www.ovh.com/fr/anti-ddos/mitigation.xml

Zero-Trust

Le modèle Zero Trust s’inscrit dans la logique de « défense en profondeur » promue historiquement par l’ANSSI, il constitue une modification du paradigme de la stricte logique périmétrique qui a longtemps prévalu. Mise en garde l’ANSSI : https://www.ssi.gouv.fr/agence/publication/le-modele-zero-trust/

Principe de moinde privilège

Ce principe vise à n’octroyer aux éléments et acteurs du système que les permissions strictement nécessaires pour fonctionner, ceci afin de limiter le risque de vol, d’altération ou de destruction de données dans le cas de compromission d’un ou plusieurs éléments. (ANSSI)

Défense en profondeur

Technique qui consite à ne pas laisser une seule couche de sécurité gérer le parfeu de sécurité. En développement logiciel, cela consiste à munir certaines briques logicielles de contrôles suplémentaires de sécurité.

Réduction de la surface d’attaque

L’ensemble des éléments techniques du SI qui peuvent être utilisés pour réaliser une attaque. Une surface d’attaque est d’autant plus large que le nombre d’éléments distincts est grand ou que ces derniers présentent des vulnérabilités exploitables par un attaquant. (ANSSI - recommandation pour la protections des système d’information essentiels)

Maintien en conditions de sécurité

Ensemble des mesures organisationnelles et techniques concourant à maintenir le niveau de sécurité d’un SI tout au long de son cycle de vie. (ANSSI - guide_protection_des_systemes_essentiels)

à compléter…​