Bonjour à tous et toutes, et bonne année.
Je viens ici pour avoir des avis SVP (des avis neutres et des avis réalistes).
Le week-end dernier, une entreprise m’a demandé de faire un léger audit. Entreprise, que je vais ci-dessous nommer "Entreprise cliente".
Tout d’abord, je résume :
Cette "Entreprise cliente" (une PME d’une dizaine de salariés) avait d’abord fait développer son logiciel web (PHP / Laravel / MySQL) par une "Agence web A".
Aujourd’hui cette "Entreprise cliente" est très dépendante de ce logiciel.
Puis un jour, cette "Entreprise cliente" a décidé d’arrêter de travailler avec "Agence web A".
Mais avant de trouver un autre prestataire pour continuer le développement et la maintenance de son logiciel, elle a (en 2024) décidée de faire appel à une "Agence B" (agence spécialisée en audits) afin de faire un audit intégrale du son logiciel web (un audit de code source PHP / Laravel).
Entre parenthèses : cette "Agence B" lui avait facturé 300 € HT de l’heure, pour un total d’environ 10 000 € HT…
Et la conclusion de leur audit est que tout était à peu prèt ok. (l’"Agence B" dit ne pas avoir trouvée d’anomalie dans le code source PHP / Laravel…).
Une fois que cette "Agence B" a fini l’audit du code source, cette "Entreprise cliente" me demande à moi aussi de regarder le code source afin que je donne mon avis. (Et cette "Entreprise cliente" m’a aussi demandé de regarder le PDF du rapport d’audit).
Donc le week-end dernier, j’ai pris une journée afin de faire un tour du code source PHP / Laravel.
Et je constate que l’audit de "Agence B", a : soit été fait à l’arrache, soit pas été fait du tout, ou soit a été fait par un développeur junior (mais vraiment très junior).
Voici un résumé de ce que j’ai pu constater comme problèmes majeurs :
(problèmes majeurs, qui n’ont pas été constatés dans l’audit de "Agence B"…)
- Génération excessive de requêtes SQL sur les pages de listing
La grande majorité des pages de listing de ce logiciel génèrent un nombre extrêmement élevé de requêtes SQL. Certaines pages génèrent des milliers de requêtes SQL (parfois + de 15 000 requêtes SQL !). Car elles ont quasiment toutes des "problèmes N+1", et certaines pages ont une absence totale de pagination, etc.
Voici un exemple :
Laravel Debugbar (un outil connu de debug pour Laravel):
http://www.laravel-cms-preprod.daw-dev.fr/medias/app/upload/Audit-exemple/Page-exemple.png
Et CPU saturé :
http://www.laravel-cms-preprod.daw-dev.fr/medias/app/upload/Audit-exemple/CPU-sature.png
Dans la 2ème image, on peut voir que le CPU du serveur est saturé à 100%.
Je précise que c’est un VPS où il y a seulement ce logiciel d’hébergement.
Et je précise aussi que (à ce moment là, lorsque j’ai pris cette impr écran) que j’étais le seul à utiliser le logiciel. Et que j’ai juste afficher une simple page de listing…
En regardant le code source, on peut très facilement voir ce problème dans (quasiment) toutes les pages de listing…
Voici un simple exemple de code source :
/**
* Problème dangereux de perf. 19 838 req SQL !
*/
public function all(Request $request)
{
// Table 'dossier_vendeur' (5300 lignes).
$dossiers = DossierVendeur::orderBy("ines", "DESC")->orderBy("ref_commercialisation", "DESC");
if(!empty($request->input("name"))) {
// ICI : problème dangereux de perf (CPU saturé).
//Car ici ça charge toutes les lignes de la table 'dossier_vendeur' (5300 lignes).
$temp_dossiers = DossierVendeur::latest()->get();
$tabDossierNames = [];
foreach($temp_dossiers as $temp){
foreach($temp->vendeurs as $vendeur) {
$tmp_name = afdt_decrypt($vendeur->last_name);
if(preg_match("/".$request->input("name")."/i", $tmp_name)){
if(!in_array($temp->id, $tabDossierNames))
$tabDossierNames[] = $temp->id;
}
}
foreach($temp->partners as $vendeur) {
$tmp_name = afdt_decrypt($vendeur->title)." ".afdt_decrypt($vendeur->last_name);
if(preg_match("/".$request->input("name")."/i", $tmp_name)){
if(!in_array($temp->id, $tabDossierNames))
$tabDossierNames[] = $temp->id;
}
}
}
if(!empty($tabDossierNames)){
$dossiers = $dossiers->whereIn("id", $tabDossierNames);
}
}
$count = $dossiers->count();
$nb_pages = $count != 0 ? ceil($count / 25) : 0;
$dossiers = $dossiers->skip($page * 25)->take(25)->get();
return view('back.dossier_vendeur.list', [
'dossiers' => $dossiers,
]);
}
(et dans le code source, quasiment toutes les pages ont ce problème, et dans le code source : c’est flagrant…).
- MySQL - Absence totale de clé étrangère dans la base de données
J’ai pu constater qu’il y a zéro clé étrangère. PS : cette BDD (MySQL) a 59 tables.
- MySQL - Absence d’indexs dans la base de données
Les seuls indexs que j’ai pu voir, sont les clés primaires, et quelques (très rares) indexs d’unicité.
- PHP / MySQL - Absence totale des transactions
J’ai pu constater une absence totale des transactions MySQL.
- Des milliers de fichiers PDF accessibles publiquement
J’ai pu constater que des milliers de fichiers PDF confidentiels, sont accessibles publiquement (sans anthentification) via une simple URL : www.domaine-du-client.fr/5658/pdf-agence/viewer
Vos avis SVP :
Maintenant, qu’en pensez-vous ?
Car pour un audit à 10k €, ne pas avoir trouvé tous ces problèmes majeurs…
Personnellement, je pense qui si l’audit aurait réellement été fait (même par un junior), que ces problèmes aurait été vu, et que l’entreprise cliente aurait été informé la gravité de la situation et sur la criticité de ces problèmes majeurs…
Merci d’avance.