vendredi 25 septembre 2026

À propos

Contact

Tests

Fuzzer sanitize_text_field et esc_html pour traquer les régressions

Une fonction d'échappement qui change subtilement de comportement d'une version à l'autre de WordPress passe souvent inaperçue. Un jeu d'entrées limites bien choisi le révèle.

Par Clément Hadrot • 11 juin 2023 • 4 min de lecture • Aucun commentaire
Fuzzer sanitize_text_field et esc_html pour traquer les régressions

Une extension d’import de contenu que nous maintenons traite des flux fournis par des partenaires tiers, avec des caractères parfois exotiques — guillemets typographiques, emojis, balises HTML mal fermées volontairement injectées par des flux mal formés. Un test unique vérifiant que sanitize_text_field('Bonjour') retourne 'Bonjour' ne dit strictement rien sur le comportement de la fonction face à ces cas réels. Un « fuzzer léger » — un jeu structuré d’entrées limites, pas un vrai outil de fuzzing aléatoire — comble ce vide sans complexité d’outillage superflue.

L’objectif n’est pas de découvrir des failles de sécurité dans le cœur de WordPress lui-même, une responsabilité qui ne relève pas d’une extension tierce, mais de vérifier que le comportement de ces fonctions reste stable et prévisible au fil des mises à jour, pour que l’extension continue de produire une sortie cohérente.

Construire le jeu d’entrées limites

Plutôt qu’un générateur aléatoire complexe, un tableau structuré de cas choisis à la main couvre déjà l’essentiel des régressions rencontrées en pratique :

public static function entrees_limites_texte(): array {
    return [
        'chaine simple'              => ['Bonjour le monde', 'Bonjour le monde'],
        'balise script'               => ['<script>alert(1)</script>', 'alert(1)'],
        'balise imbriquee cassee'     => ['<b><i>texte</b>', 'texte'],
        'guillemets typographiques'  => ['« citation »', '« citation »'],
        'emoji multioctet'            => ['Bravo 🎉 équipe', 'Bravo 🎉 équipe'],
        'espace insecable'            => ["Prix : 42\u{00A0}€", "Prix : 42\u{00A0}€"],
        'saut de ligne interne'       => ["Ligne un\nLigne deux", 'Ligne un Ligne deux'],
        'chaine vide'                 => ['', ''],
        'uniquement des espaces'      => ['   ', ''],
    ];
}

Tester sanitize_text_field sur l’ensemble du jeu

#[DataProvider('entrees_limites_texte')]
public function test_sanitize_text_field_comportement_stable(string $entree, string $attendu): void {
    $resultat = sanitize_text_field($entree);

    $this->assertSame($attendu, $resultat);
}
L'essentiel à retenir : Générer des entrées limites plutôt qu'une seule chaîne de test ; Couvrir les caractères multioctets et les balises imbriquées ; Figer le comportement attendu version par version de WordPress

Ce test ne vérifie pas que sanitize_text_field() fonctionne « bien » dans l’absolu — WordPress s’en charge en interne — mais qu’aucune évolution de version n’a modifié silencieusement un comportement sur lequel l’extension s’appuie explicitement, par exemple la normalisation des sauts de ligne en espaces simples.

Le même principe appliqué à esc_html

public static function entrees_limites_html(): array {
    return [
        'esperluette seule'          => ['Café & Thé', 'Café & Thé'],
        'chevrons imbriques'          => ['a < b > c', 'a &lt; b &gt; c'],
        'guillemet double'            => ['Il a dit "stop"', 'Il a dit "stop"'],
        'apostrophe typographique'   => ["l'équipe", 'l'équipe'],
    ];
}

#[DataProvider('entrees_limites_html')]
public function test_esc_html_comportement_stable(string $entree, string $attendu): void {
    $this->assertSame($attendu, esc_html($entree));
}

Pourquoi ces cas précis et pas d’autres

  • Les balises imbriquées et mal fermées reproduisent des flux de contenu réellement reçus de partenaires externes, une source d’entrée moins contrôlée qu’une saisie utilisateur classique.
  • Les caractères multioctets (emojis, accents) vérifient l’absence de troncature ou de corruption d’encodage, un risque réel selon la configuration de charset de la base de données cible.
  • Les cas d’entrée vide ou uniquement composée d’espaces couvrent une classe d’erreurs fréquente où un traitement en aval suppose à tort qu’une chaîne non vide en entrée reste non vide après nettoyage.

Faire tourner ce test à chaque montée de version de WordPress

Ce test prend tout son sens intégré à un pipeline qui installe une nouvelle version mineure ou majeure de WordPress avant de lancer la suite : une différence inattendue sur l’un de ces cas limites alerte immédiatement, avant que l’extension ne soit distribuée à des clients avec un comportement de nettoyage de texte subtilement différent de celui prévu au moment du développement initial.

Un test de fonction native comme sanitize_text_field ne cherche pas à corriger WordPress — il cherche à documenter, de façon vérifiable, ce que l’extension suppose vrai à son sujet, pour être alerté le jour où cette supposition cesse de l’être.

Ce que cette approche ne couvre pas

Ce jeu de cas limites vérifie la stabilité de comportement de fonctions d’échappement précises, pas la stratégie globale de sécurisation des sorties d’une extension, qui implique aussi de choisir la bonne fonction selon le contexte (HTML, attribut, URL, JavaScript) — un sujet plus large déjà traité séparément.

En résumé

Vingt-quatre cas limites bien choisis, répartis entre sanitize_text_field et esc_html, suffisent à transformer une confiance implicite en garantie vérifiable à chaque mise à jour de WordPress. Ce test coûte peu à écrire une fois le jeu de données construit, et continue de protéger le projet longtemps après que la personne qui l’a écrit soit passée à autre chose.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi