Le WordPress d'aujourd'hui, décodé pour les développeurs

Extensions

esc_html contre esc_attr : l’échappement qui ne correspond pas au contexte

Un échappement techniquement présent mais mal choisi laisse parfois passer une faille XSS discrète. Contextes mal appariés et bonne fonction pour chacun.

Par WordPress Développement • 15 février 2021 • 4 min de lecture • Aucun commentaire
esc_html contre esc_attr : l'échappement qui ne correspond pas au contexte

Warning: esc_attr() used where esc_html() was expected — ce message n’existe pas dans WordPress, et c’est bien tout le problème : un mauvais choix d’échappement ne provoque aucune alerte. Le code s’exécute normalement, la page s’affiche, et la faille reste invisible tant que personne n’injecte volontairement une charge malveillante dans le bon champ.

L’échappement en sortie est la dernière ligne de défense contre les failles de type XSS (injection de script). Le principe est simple : ne jamais afficher une donnée provenant de l’utilisateur, d’une base de données ou d’une API tierce sans l’échapper au moment précis où elle est écrite dans le HTML. Mais un principe simple ne suffit pas si la fonction choisie ne correspond pas au contexte réel de sortie.

Ce que chaque fonction attend réellement

esc_html() convertit les caractères spéciaux HTML (<, >, &) pour qu’une donnée s’affiche comme du texte brut à l’intérieur d’un élément, sans jamais être interprétée comme une balise. esc_attr() fait quelque chose de proche, mais avec un objectif différent : elle prépare une valeur pour qu’elle soit insérée à l’intérieur d’un attribut HTML, entre guillemets, en neutralisant en plus les guillemets eux-mêmes.

Le piège vient de leur ressemblance apparente. Les deux fonctions échappent des caractères proches, ce qui donne l’impression qu’elles sont interchangeables. Elles ne le sont pas : chacune est pensée pour un contexte de sortie précis, et l’inverser laisse passer des cas que l’autre fonction aurait bloqués.

L'essentiel à retenir : Un échappement présent n'est pas toujours un échappement correct ; Chaque contexte de sortie a sa propre fonction dédiée ; esc_attr échoue silencieusement dans un contenu HTML libre

Un exemple de contexte mal apparié

// Incorrect : esc_attr() utilisée pour un contenu affiché comme texte
echo '<p>' . esc_attr( $commentaire_utilisateur ) . '</p>';

// Correct pour ce contexte
echo '<p>' . esc_html( $commentaire_utilisateur ) . '</p>';

Dans ce premier cas, esc_attr() échappe correctement les guillemets, mais son comportement sur certains caractères diffère légèrement de celui attendu pour un contenu texte libre. Le résultat s’affiche presque toujours correctement à l’œil, ce qui rend l’erreur difficile à détecter en relecture visuelle — elle ne saute aux yeux que lors d’un audit de sécurité ciblé ou d’un test d’intrusion.

L’inverse est tout aussi problématique

// Incorrect : esc_html() utilisée pour un attribut
echo '<input type="text" value="' . esc_html( $valeur ) . '">';

// Correct pour un attribut
echo '<input type="text" value="' . esc_attr( $valeur ) . '">';

Ici, le risque est plus direct : esc_html() n’échappe pas systématiquement tous les guillemets doubles de la même manière qu’esc_attr(), ce qui peut, selon la valeur injectée, permettre de sortir prématurément de l’attribut et d’ajouter un attribut supplémentaire, voire un gestionnaire d’événement, à l’élément HTML.

Panorama des fonctions selon le contexte

Contexte de sortieFonction correcteErreur fréquente
Texte entre deux balisesesc_html()Utiliser esc_attr()
Valeur d’un attribut HTMLesc_attr()Utiliser esc_html()
URL dans un attribut href ou srcesc_url()Utiliser esc_attr() seule
Bloc de JavaScript inlineesc_js()Utiliser esc_html()
Contenu HTML riche autoriséwp_kses_post()Aucun échappement du tout

Ce qu’il faut retenir pour éviter l’erreur

La règle la plus fiable ne consiste pas à mémoriser des cas particuliers, mais à se poser une seule question à chaque ligne d’affichage : où, précisément, cette donnée atterrit-elle dans le HTML généré ? À l’intérieur d’une balise ouvrante et fermante, entre guillemets d’un attribut, dans une URL, ou dans un bloc de script. La réponse détermine la fonction, sans exception.

  • Ne jamais choisir une fonction d’échappement par habitude, mais par contexte de sortie.
  • Ne jamais réutiliser une valeur déjà échappée pour un autre contexte sans la ré-échapper correctement.
  • Toujours tester avec une valeur contenant des guillemets et des chevrons, pas seulement du texte ordinaire.

Un code qui échappe systématiquement, même mal, donne un faux sentiment de sécurité bien plus dangereux qu’une absence totale d’échappement, repérée immédiatement lors d’une relecture.

En résumé

Un échappement mal apparié à son contexte reste, à l’œil, indiscernable d’un échappement correct. La seule protection réelle consiste à connaître précisément ce que chaque fonction native attend en entrée et où elle est censée être utilisée en sortie, puis à appliquer cette règle systématiquement, sans raccourci, sur chaque donnée affichée.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

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

Voir tous ses articles

Dans la même veine

À lire aussi