Situation actuelle : PHP2Shell. Deux failles PHP critiques (CVSS 9.2) permettent d'exécuter du code malveillant sans authentification. Correctifs disponibles depuis le 21 octobre 2026.Ce qu'il faut faire maintenant →

Valider et filtrer les saisies en PHP avec filter_var

Comment les développeurs contrôlent les saisies en PHP avec filter_var, filter_input_array et des listes autorisées, quels filtres sont obsolètes et pourquoi la validation ne remplace ni les requêtes préparées ni l'encodage en sortie.

État 7 min de lectureDéveloppement sécurisé

En bref : vous validez les saisies en PHP avec filter_var() ou filter_input_array() et des règles claires pour chaque champ : type, plage, longueur et valeurs autorisées. Ce qui ne correspond pas est rejeté, et non remanié en silence. La validation est importante pour des données propres et une surface d'attaque réduite, mais elle ne remplace ni les requêtes préparées contre l'injection SQL, ni l'encodage adapté au contexte contre XSS.

Pourquoi « tout filtrer » n'est pas une stratégie

Dans de nombreux anciens projets PHP, on trouve au début de chaque fichier une boucle qui fait passer toutes les valeurs de $_GET et $_POST par une fonction de nettoyage. Cela donne une impression de sécurité. En pratique, elle supprime tantôt trop, par exemple les apostrophes dans les noms de famille, tantôt trop peu, car la même fonction doit valoir en même temps pour SQL, HTML et les noms de fichiers.

Une validation judicieuse procède autrement : elle demande, pour chaque champ, ce qui y est autorisé. Une quantité commandée est un entier compris entre 1 et une limite supérieure. Un champ de tri est l'une de trois valeurs fixes. Une date a un format précis et se situe après une autre date. Tout le reste est rejeté.

L'OWASP distingue deux niveaux : le contrôle syntaxique, qui vérifie qu'une valeur a la bonne forme, et le contrôle sémantique, qui vérifie qu'elle a du sens dans le contexte. Les deux relèvent du serveur ; les contrôles dans le navigateur ne servent qu'à la commodité d'usage.

Les filtres fournis par PHP

L'extension Filter est incluse par défaut dans PHP. Les principaux filtres de validation selon le manuel PHP :

Filtre Vérifie Options importantes et remarques
FILTER_VALIDATE_INT entier min_range, max_range
FILTER_VALIDATE_FLOAT nombre décimal decimal pour le séparateur
FILTER_VALIDATE_BOOL valeur booléenne avec FILTER_NULL_ON_FAILURE, distinguable de « faux »
FILTER_VALIDATE_EMAIL forme d'une adresse e-mail ne prouve pas que la boîte aux lettres existe
FILTER_VALIDATE_URL forme d'une URL vérifier soi-même le schéma, pas de domaines internationalisés
FILTER_VALIDATE_IP adresse IP indicateurs pour les plages privées et réservées
FILTER_VALIDATE_REGEXP motif personnalisé ancrer le motif avec ^ et $

Le filtre de nettoyage FILTER_SANITIZE_STRING est obsolète depuis PHP 8.1. Si vous l'utilisez encore, migrez la validation vers des filtres adaptés et employez htmlspecialchars() pour l'affichage.

filter_var en PHP : contrôler proprement un formulaire

Avec filter_input_array(), on peut contrôler un formulaire entier en une seule étape par rapport à une définition. Les champs inconnus ne sont pas repris :

<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // afficher un message d'erreur par champ, ne pas traiter les saisies
}

Notez les comparaisons strictes avec === : une valeur valide 0 ou une chaîne vide ne doit pas être confondue avec un échec. Pourquoi les comparaisons lâches sont ici dangereuses est expliqué dans Type juggling : les comparaisons lâches comme risque de sécurité. La façon dont PHP met à disposition les données de requête est décrite dans Superglobales : $_GET, $_POST, $_FILES et autres.

Pièges avec les e-mails, les URL et les textes libres

Certains filtres font moins que ce que leur nom laisse supposer :

  1. URL : FILTER_VALIDATE_URL accepte aussi d'autres schémas que http et https. Vérifiez ensuite le schéma avec parse_url() par rapport à une liste fixe. Si l'URL est appelée par le serveur, des règles supplémentaires s'appliquent, voir Empêcher le Server-Side Request Forgery en PHP.
  2. Adresses e-mail : le filtre vérifie la forme, pas la propriété. Qui a besoin d'être certain envoie un lien de confirmation.
  3. Texte libre : noms, messages et adresses se laissent difficilement restreindre de façon pertinente à certains caractères. Contrôlez la longueur et l'encodage des caractères, par exemple avec mb_check_encoding($wert, 'UTF-8'), et fiez-vous à l'encodage à l'affichage.
  4. Expressions régulières : sans ^ et $, un motif vérifie seulement s'il apparaît quelque part dans le texte, et non si la valeur entière correspond.
  5. Tableaux au lieu de chaînes : un attaquant peut envoyer un tableau au lieu d'un texte. Sans contrôle de type, cela provoque des avertissements ou un comportement inattendu.
Astuce

Pour des valeurs de sélection fixes comme le tri, la langue ou le mode d'expédition, une liste autorisée avec in_array($wert, $erlaubt, true) ou une expression match est plus simple et plus stricte que n'importe quelle expression régulière.

Une autre erreur fréquente concerne les nombres porteurs de sens, comme les prix, les quantités ou les remises. Qu'une valeur soit un nombre valide ne dit rien sur son autorisation dans le contexte. Une quantité négative, une remise supérieure à la valeur de la marchandise ou un prix repris du formulaire au lieu de la base de données sont des erreurs de logique classiques. Les prix, les autorisations et les valeurs d'état relèvent donc toujours du serveur, jamais de champs de formulaire cachés.

JSON, webhooks et imports : la validation au-delà des formulaires

De nombreuses entrées ne sont plus aujourd'hui des formulaires, mais des requêtes JSON d'applications, des webhooks de services de paiement ou des fichiers d'import de fournisseurs. Là aussi : d'abord lire en toute sécurité, ensuite contrôler. L'OWASP conseille de limiter la taille et la profondeur d'imbrication avant même de lire les données. En PHP, json_decode() avec une profondeur maximale et JSON_THROW_ON_ERROR en assure une partie :

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // 64 Ko au maximum
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}

Pour les webhooks, avant le contrôle du contenu se pose la question de savoir si le message provient réellement du service indiqué. Si le service propose une signature, vérifiez-la et comparez-la avec hash_equals(). Pour les fichiers d'import, contrôlez chaque ligne comme un formulaire et interrompez proprement en cas d'erreur, au lieu de reprendre des enregistrements à moitié valides.

Les messages d'erreur devraient nommer le champ concerné, mais ne pas renvoyer telle quelle la valeur rejetée. Sinon, le message d'erreur lui-même devient un nouveau point de sortie qu'il faudra encoder à nouveau.

Ce que la validation ne peut pas faire

La validation réduit la surface d'attaque, mais, selon l'OWASP, elle n'est pas la défense principale contre l'injection. Un nom de famille avec apostrophe est valide et doit pourtant arriver sans danger dans une base de données. Cela n'est possible qu'avec des requêtes préparées, comme le montre le guide Empêcher l'injection SQL en PHP. Et un texte de commentaire valide ne devient inoffensif que par un encodage adapté au contexte à l'affichage.

Le bon ordre est donc : valider à la réception, paramétrer au traitement, encoder à l'affichage. S'y ajoutent des limites de taille en amont : le serveur web et PHP ne devraient même pas traiter entièrement des requêtes beaucoup trop volumineuses. Des réglages comme post_max_size y contribuent et devraient de toute façon être vérifiés après PHP2Shell.

Comment PHP SOS aide-t-il concrètement ?

  • Nous recensons toutes les entrées de votre application : formulaires, interfaces, téléversements, imports et webhooks.
  • Nous définissons pour chaque champ ce qui est autorisé et remplaçons les fonctions de nettoyage généralisées par des contrôles clairs.
  • Nous vérifions si les accès à la base de données et les sorties sont sécurisés indépendamment de la validation.
  • Nous documentons les règles de façon que votre équipe puisse les poursuivre pour les nouvelles fonctions.

Une vérification systématique est décrite dans la prestation audit de sécurité et test d'intrusion.

Questions fréquentes

Quelle est la différence entre valider et nettoyer ?

Valider consiste à vérifier si une valeur correspond aux attentes et à la rejeter sinon. Nettoyer modifie la valeur, par exemple en supprimant des caractères. Pour les décisions de sécurité, rejeter est presque toujours préférable, car une valeur modifiée en silence peut engendrer de nouvelles erreurs.

FILTER_SANITIZE_STRING est-il encore utilisable ?

Le filtre est marqué comme obsolète depuis PHP 8.1. Le manuel PHP recommande à la place htmlspecialchars() à l'affichage. Vous devriez migrer le code existant, car les fonctions obsolètes peuvent disparaître dans les versions futures.

FILTER_VALIDATE_URL suffit-il à sécuriser les liens ?

Non. Le filtre ne vérifie que la forme de l'adresse. Selon le manuel, une URL valide ne doit pas nécessairement commencer par http ; vous devez donc contrôler vous-même le schéma par rapport à une liste autorisée comme https. Le filtre rejette les noms de domaine internationalisés.

Dois-je aussi valider les données de ma propre base de données ?

À l'affichage, elles sont considérées comme non fiables et encodées en conséquence. Une nouvelle validation a du sens lorsque les données proviennent à l'origine de l'extérieur et sont désormais utilisées dans un nouveau contexte, par exemple comme nom de fichier ou partie d'une commande.

La validation aide-t-elle contre PHP2Shell ?

Non. PHP2Shell concerne le traitement des requêtes dans l'interpréteur PHP, avant même que le code de votre application ne s'exécute. Seule la mise à jour de PHP, suivie du redémarrage de tous les processus PHP, y remédie.

Sources

Contact immédiat

Chaque heure compte. Écrivez-nous maintenant.

Décrivez brièvement votre système, votre version de PHP et ce que vous avez observé. Nous vous répondons, faisons le point et travaillons à distance jusqu'à la clôture et la documentation de l'incident.

Aide immédiate