
La plupart des failles d'une application PHP viennent d'une poignée d'erreurs : requêtes SQL construites avec les données de l'utilisateur, affichage sans échappement, formulaires sans jeton CSRF, envoi de fichiers mal contrôlé, sessions mal protégées, droits d'accès non vérifiés et dépendances obsolètes. Chacune se corrige avec des pratiques simples.
Sommaire
Quand je réalise un audit de sécurité sur une application PHP, ce sont presque toujours les mêmes failles qui reviennent, qu’il s’agisse d’un CRM interne, d’un espace client ou d’un ancien projet sans framework. La bonne nouvelle : chacune se corrige avec des pratiques simples et bien connues. Voici les plus courantes, avec le code pour sécuriser une application PHP.
1. L’injection SQL
C’est la faille classique : une requête construite en collant directement une donnée envoyée par l’utilisateur. Un attaquant peut alors lire, modifier ou supprimer la base de données.
// À éviter
$sql = "SELECT * FROM clients WHERE id = " . $_GET['id'];
// Requête préparée avec PDO
$stmt = $pdo->prepare( 'SELECT * FROM clients WHERE id = :id' );
$stmt->execute( [ 'id' => $_GET['id'] ] );
Règle simple : aucune donnée extérieure ne doit être concaténée dans une requête. Les noms de colonnes ou de tri, qui ne peuvent pas être préparés, se contrôlent avec une liste de valeurs autorisées.
2. Le XSS (injection de script)
Une donnée affichée sans échappement peut contenir du JavaScript, exécuté dans le navigateur des autres utilisateurs ou des administrateurs. Échappez au moment de l’affichage, selon le contexte :
echo htmlspecialchars( $nom, ENT_QUOTES, 'UTF-8' );
Un moteur de templates comme Twig ou Blade échappe automatiquement. Une politique de sécurité du contenu (en-tête Content-Security-Policy) ajoute une seconde barrière.
3. Les formulaires sans protection CSRF
Sans jeton, un site tiers peut faire envoyer un formulaire à votre application par un utilisateur connecté, à son insu : changement d’email, suppression, virement. Chaque formulaire qui modifie des données doit contenir un jeton aléatoire, stocké en session et vérifié à la réception :
$_SESSION['csrf'] ??= bin2hex( random_bytes( 32 ) );
// À la réception :
if ( ! hash_equals( $_SESSION['csrf'], $_POST['csrf'] ?? '' ) ) {
http_response_code( 403 );
exit;
}
4. L’envoi de fichiers
Un formulaire d’envoi mal contrôlé permet de déposer un script PHP sur le serveur, puis de l’exécuter. Les règles :
- Vérifier le vrai type du fichier avec
finfo, pas l’extension ni le type annoncé par le navigateur. - Renommer le fichier avec un nom généré, et n’accepter qu’une liste fermée d’extensions.
- Stocker les fichiers hors du dossier public, ou dans un dossier où l’exécution de PHP est désactivée.
- Limiter la taille.
5. Les mots de passe et les sessions
- Stocker les mots de passe avec
password_hash()et les vérifier avecpassword_verify(). Jamais de MD5 ni de SHA1, même « salés ». - Appeler
session_regenerate_id( true )juste après la connexion, pour éviter la fixation de session. - Configurer les cookies de session avec les attributs
HttpOnly,SecureetSameSite. - Limiter les tentatives de connexion pour freiner les attaques par force brute.
6. Les droits d’accès non vérifiés
C’est la faille que je trouve le plus souvent dans les applications métier : la page facture.php?id=125 vérifie que l’utilisateur est connecté, mais pas que la facture 125 lui appartient. Il suffit de changer le numéro pour voir les données d’un autre client. Chaque accès à une ressource doit vérifier les droits de l’utilisateur sur cette ressource, côté serveur.
7. La configuration et les erreurs
- En production,
display_errorsdoit être désactivé : les messages d’erreur révèlent des chemins, des requêtes et parfois des identifiants. Les erreurs vont dans un journal. - Les identifiants (base de données, API) se rangent hors du dossier public, par exemple dans un fichier
.envnon accessible depuis le web, et jamais dans le dépôt Git. - Le site doit être servi uniquement en HTTPS, avec l’en-tête HSTS.
8. Les dépendances et la version de PHP
Une bibliothèque vulnérable expose toute l’application. Avec Composer, la commande composer audit liste les paquets concernés par une faille connue. La version de PHP compte aussi : une version qui ne reçoit plus de correctifs de sécurité expose le serveur. Si votre application tourne encore en PHP 7, voyez le guide passer de PHP 7 à PHP 8.
Par où commencer
- Lister les points d’entrée : formulaires, paramètres d’URL, API, envois de fichiers.
- Vérifier les requêtes SQL et les affichages de données, ce sont les failles les plus graves et les plus faciles à corriger.
- Contrôler les droits d’accès sur chaque page qui affiche ou modifie des données.
- Mettre à jour PHP et les dépendances.
Un regard extérieur fait souvent gagner beaucoup de temps : un audit de sécurité du code PHP classe les failles par gravité et donne la correction de chacune.
Questions fréquentes
Un framework comme Laravel ou Symfony suffit-il à sécuriser l’application ?
Il apporte de bonnes protections par défaut (requêtes préparées, échappement, jetons CSRF), mais il ne vérifie pas vos règles métier. Les droits d’accès, la gestion des fichiers et la configuration restent sous votre responsabilité.
Mon application est ancienne et sans framework, faut-il tout réécrire ?
Pas forcément. Les failles les plus graves se corrigent souvent de façon ciblée. L’audit permet de décider entre une sécurisation progressive et une réécriture partielle.


