
La première chose que je regarde quand j'audite une application PHP, c'est le composer.json. Les versions. Le cadre temporel du projet en deux lignes.
Sur celui-ci, une plateforme de billetterie événementielle open-source encore en production, les deux premières lignes ont suffi : PHP 7.3. Laravel 6. Deux technologies officiellement mortes depuis 2022.
Le projet tournait. Les billets se vendaient. Personne ne s'inquiétait.
C'est souvent comme ça. Un projet bien construit à son époque, une équipe qui passe à autre chose, et le code qui continue de tourner, comme un immeuble dont le gardien est parti. Les fissures s'installent, mais de l'extérieur, la façade tient.
J'ai poussé l'audit jusqu'au bout. Score final : 19 sur 100. Voilà ce que j'ai trouvé sous le capot.
PHP 7.3, Laravel 6 : deux cadavres qui marchent encore
PHP 7.3, fin de vie depuis décembre 2021. Laravel 6, même sort depuis septembre 2022. Au moment de l'audit, ça fait plus de trois ans que ces deux-là ne reçoivent plus aucun correctif. Ni fonctionnel, ni sécurité. Rien.
Et le projet tourne toujours.
C'est le piège classique : tant que ça marche, on n'y touche pas. Pas de bug visible, pas de ticket urgent, d'autres priorités. Sauf que "ça marche" et "c'est sûr", c'est pas la même chose, et l'écart se creuse silencieusement.
Cette situation n'a rien d'exceptionnel. PHP 7.4, la dernière version de la branche 7, a atteint sa fin de vie en novembre 2022. Si votre application tourne encore dessus, vous êtes dans le même bateau.
Et le framework qui va avec n'est pas en meilleur état. Quand le langage et le framework sont en fin de vie, chaque jour qui passe élargit la surface d'attaque. Sans que personne ne s'en rende compte.
72 CVE, et personne au courant
Un CVE, c'est une faille de sécurité identifiée et cataloguée publiquement. Le genre de truc qu'un attaquant peut exploiter en suivant un tuto.
Sur ce projet, j'en ai compté 72. Répartis sur 19 packages. Dont certains permettent l'exécution de code à distance, le niveau le plus critique.
Le composer.lock, c'est censé être un congélateur : on fige les versions pour que l'application reste stable. Sauf que quand personne ne met à jour, le congélateur tombe en panne et le contenu pourrit. Les dépendances vieillissent même si personne ne touche au code. Les failles s'accumulent. Et aucune alerte ne remonte : pas de Dependabot configuré, pas d'audit automatique, rien dans le quotidien du projet qui signale le problème.
72 CVE, c'est pas un oubli. C'est des années d'inertie. Et le pire, c'est que vu de l'extérieur, tout a l'air normal.
492 erreurs d'analyse statique, au niveau le plus permissif
PHPStan, c'est un outil d'analyse statique : il lit votre code sans l'exécuter et remonte tout ce qui ne tourne pas rond. Types incohérents, appels de méthodes sur des objets qui n'existent peut-être pas, variables mortes. Il a 10 niveaux de sévérité : le niveau 1 est le plus tolérant.
J'ai lancé PHPStan au niveau 1 sur ce projet. 492 erreurs.
Pour donner une idée : au niveau 1, PHPStan ne signale que les problèmes les plus grossiers. C'est le détecteur de fumée le moins sensible du marché, et là, il hurlait.
Les problèmes ne sont pas localisés dans un coin du code. Ils sont partout. Et quand on zoome, on comprend pourquoi : un contrôleur de 822 lignes qui gère à lui seul le paiement, les commandes et les statistiques. Trois fichiers dépassent les 500 lignes. Le code a grandi fonctionnalité après fonctionnalité, sans que personne ne restructure.
Ce n'est pas un projet bâclé. C'est un projet qui a fonctionné, qui a rendu service, et que personne n'a entretenu. La différence est importante.
11 tests pour 132 fichiers, bonne chance
11 fichiers de test. 132 fichiers source. Ratio : 0.08. Autrement dit, pour chaque fichier testé, il y en a douze qui volent sans filet.
Chaque modification sur ce projet est un coup de poker. Corriger un bug dans le paiement ? Aucun moyen de savoir si ça casse autre chose. Ajouter une fonctionnalité ? Bonne chance, il faut tout vérifier à la main.
Et c'est là que le cercle vicieux s'installe : plus le code est fragile, moins on ose y toucher. Moins on y touche, moins on écrit de tests. Moins il y a de tests, plus le code est fragile. Au bout de quelques années, on se retrouve avec une application que personne ne veut maintenir, pas par paresse, mais parce que le risque de casser quelque chose est devenu trop élevé.
Et même quand des tests existent, encore faut-il qu'ils détectent les vrais bugs. Un test peut passer au vert et ne rien vérifier du tout. C'est tout le problème que le mutation testing cherche à résoudre.
Ici, on n'en est même pas là. Le filet de sécurité n'existe tout simplement pas.
\Exeption, le bug qui ne dit pas son nom
Celui-là, je l'ai trouvé dans le flux de paiement. Pas dans un coin anodin, dans le code qui gère les transactions.
Un bloc try/catch qui attrape \Exeption au lieu de \Exception. Une lettre manquante. PHP ne dit rien : le namespace n'existe pas, donc le catch ne rattrape jamais rien. Les erreurs passent, silencieusement. Le paiement plante, et personne n'est prévenu.
C'est le genre de bug qui peut dormir pendant des mois. Pas d'erreur affichée, pas de log, pas d'alerte. Il faut tomber dessus pour le voir, et dans 822 lignes de code, faut avoir l'oeil.
Et ce n'est pas le seul fantôme dans les placards. L'audit a aussi relevé une injection SQL, le genre de faille qui n'a rien à faire dans du code en production.
Quand le code échoue sans prévenir et que les failles restent ouvertes, ce n'est plus de la dette technique. C'est un risque opérationnel.
19/100, et votre projet ?
Score final de l'audit : 19 sur 100.
Un langage et un framework en fin de vie depuis plus de trois ans. 72 CVE dans les dépendances. 492 erreurs d'analyse statique au niveau le plus permissif. 11 tests pour 132 fichiers. Un bug invisible dans le flux de paiement. Une injection SQL.
Ce projet n'est pas un cas isolé. C'est un cas documenté.
La plupart des applications PHP vieillissantes présentent plusieurs de ces signaux, à des degrés divers. La question n'est pas de savoir si votre projet a de la dette technique. La question, c'est : combien de cases vous cochez ?
- Votre version de PHP est en fin de vie ?
- Vos dépendances ont des CVE non corrigées ?
- Votre couverture de tests est anecdotique ?
- Des erreurs passent sans laisser de trace dans vos logs ?
Deux cases cochées, et il est probablement temps d'ouvrir le capot.
Pas de panique, de la lucidité. Ces signaux sont courants, et surtout, ils sont détectables. Un audit structuré les identifie rapidement. Ce qui coûte cher, ce n'est pas le diagnostic, c'est d'attendre que le problème se manifeste en production un vendredi soir.
Pour éviter d'en arriver là, ça vaut le coup d'automatiser la qualité et la sécurité dès le commit.
Si vous reconnaissez ces signaux dans votre projet, faites-moi signe, c'est le genre de diagnostic qui se fait en quelques jours.