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

Sécurité

Un annuaire de praticiens : un champ rendu public par erreur

Un champ de coordonnées internes destiné aux seuls administrateurs se retrouvait accessible à tout le monde via l'API REST d'un annuaire de praticiens.

Par WordPress Développement • 3 septembre 2022 • 5 min de lecture • Aucun commentaire
Un annuaire de praticiens : un champ rendu public par erreur

Pourquoi un champ personnalisé destiné à un usage strictement interne finit-il par apparaître dans une réponse JSON publique ? C’est la question posée par un annuaire de praticiens qui recensait plus de quatre cents fiches, chacune enrichie de coordonnées internes réservées au secrétariat : ligne directe, poste de standard, note de disponibilité. Ces informations n’avaient rien à faire devant les yeux d’un visiteur, et pourtant elles s’y trouvaient.

Le point de départ n’est pas une faille exotique ni une extension compromise. C’est un enregistrement de champ personnalisé fait un peu vite, avec l’option show_in_rest activée sans réflexion sur qui devait pouvoir la lire. Ce cas illustre un piège récurrent dans les projets WordPress qui exposent une API REST : la facilité d’exposition d’un champ ne dit rien de la façon dont il doit être protégé.

Ce que l’API REST révélait sans le vouloir

L’annuaire reposait sur un type de contenu personnalisé praticien, interrogeable via l’endpoint standard /wp-json/wp/v2/praticien. Chaque fiche embarquait un groupe de champs personnalisés enregistrés avec register_post_meta(), dont un champ ligne_directe pensé pour un usage interne. Le développeur avait déclaré ce champ ainsi :

register_post_meta( 'praticien', 'ligne_directe', array(
    'type'         => 'string',
    'single'       => true,
    'show_in_rest' => true,
) );

Rien dans cette déclaration ne limite la lecture à un rôle particulier. Dès que show_in_rest vaut true, WordPress ajoute le champ à la sortie JSON pour quiconque interroge l’endpoint, y compris un visiteur non authentifié. Un simple appel curl sur l’URL publique de l’annuaire suffisait à récupérer la ligne directe de chaque praticien, information jamais destinée à figurer sur le site public.

Le contrôle de capacité qui manquait

L'essentiel à retenir : Un champ meta mal protégé fuit par défaut dans la réponse REST ; show_in_rest ne suffit pas sans contrôle de capacité ; auth_callback doit vérifier le rôle avant chaque lecture

La correction ne consiste pas à retirer show_in_rest, ce qui aurait aussi empêché l’éditeur de blocs et les futurs usages légitimes de l’API d’accéder au champ en back-office. La bonne approche est de fournir un tableau de configuration détaillé plutôt qu’un simple booléen, avec un auth_callback qui vérifie la capacité de l’utilisateur courant :

register_post_meta( 'praticien', 'ligne_directe', array(
    'type'          => 'string',
    'single'        => true,
    'show_in_rest'  => true,
    'auth_callback' => function() {
        return current_user_can( 'edit_posts' );
    },
) );

Avec ce callback, show_in_rest continue de rendre le champ disponible dans le schéma de l’API, mais sa valeur n’est renvoyée que si l’utilisateur authentifié dispose de la capacité edit_posts. Un visiteur anonyme reçoit toujours l’entrée dans la structure JSON, avec une valeur vide, jamais la donnée elle-même.

Vérifier le comportement avant et après correctif

Le test le plus simple consiste à interroger l’endpoint sans authentification et à comparer la réponse avant et après la modification :

  • Avant correctif : le champ ligne_directe contient la valeur réelle, visible par n’importe qui.
  • Après correctif : le champ existe toujours dans la structure de réponse, mais sa valeur est vide pour un appel anonyme.
  • Après correctif, en tant qu’éditeur connecté via l’authentification par cookie de l’admin REST, la valeur réelle redevient visible.

Ce test doit être systématique dès qu’un champ personnalisé touche à une donnée qui n’est pas destinée au grand public, qu’il s’agisse d’un numéro de téléphone, d’une note interne ou d’un tarif préférentiel.

Étendre la vérification à tout l’annuaire

Un seul champ corrigé ne suffit pas si le même schéma d’enregistrement a été copié-collé sur d’autres métadonnées. L’audit complet de l’annuaire a fait remonter deux autres champs dans la même situation : une note de disponibilité interne et un identifiant de dossier RH. Chacun a reçu le même traitement, avec un auth_callback adapté à la sensibilité réelle de la donnée : certains champs restent lisibles par tout contributeur, d’autres sont réservés aux administrateurs via current_user_can( 'manage_options' ).

Il est utile de constituer une liste de vérification avant toute mise en production d’un annuaire ou d’un catalogue exposé en REST :

  • Lister tous les register_post_meta() et register_rest_field() du projet.
  • Pour chacun, se demander explicitement : « cette donnée peut-elle être vue par un visiteur anonyme ? »
  • Ajouter un auth_callback dès que la réponse est négative, même si la donnée semble anodine aujourd’hui.

Sur nos projets, tout champ personnalisé exposé en REST passe désormais par une revue explicite de sa visibilité avant la mise en ligne, plutôt qu’un ajustement après coup une fois le problème signalé.

Ce que révèle ce type d’incident

Ce cas n’a rien d’unique aux annuaires de praticiens : toute base de données WordPress qui mélange des informations publiques et des informations de gestion interne dans un même type de contenu est exposée au même risque. La cause profonde n’est pas une négligence isolée, mais une confusion entre deux questions différentes : « ce champ doit-il exister dans l’API REST ? » et « qui a le droit de lire sa valeur ? ». show_in_rest répond à la première question, auth_callback répond à la seconde, et confondre les deux revient à laisser la porte grande ouverte.

En résumé

Corriger l’exposition a pris moins d’une heure une fois le champ identifié. Le trouver a pris davantage de temps, car rien dans l’interface d’administration ne signale qu’un champ personnalisé fuit publiquement : il faut interroger l’API comme le ferait un visiteur non authentifié pour s’en rendre compte. C’est ce réflexe d’audit, plus que le correctif lui-même, qui mérite d’être intégré à chaque projet exposant des données via l’API REST de WordPress.

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