# Verrouiller les capacités REST : ce que show_in_rest expose sans le vouloir

> Activer show_in_rest sur un type de contenu personnalisé expose parfois des champs privés à n'importe quel visiteur non authentifié. Checklist des réglages à vérifier avant publication.

- Auteur : Clément Hadrot
- Publié le : 2021-12-29
- Mis à jour le : 2021-12-29
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/show-in-rest-champs-prives-exposes-checklist/

## L’essentiel

- show_in_rest expose plus que le contenu public par défaut
- Les métadonnées suivent des règles d'exposition séparées
- Une checklist avant mise en ligne évite la découverte a posteriori

Un site immobilier gère ses biens en vente via un type de contenu personnalisé `bien_immobilier`, avec l'option `show_in_rest` activée pour permettre à l'application mobile du client de consommer les données via l'API REST de WordPress. Tout fonctionne comme prévu, jusqu'à ce qu'un développeur externe, en explorant simplement l'URL `/wp-json/wp/v2/bien_immobilier`, remarque que chaque entrée renvoie non seulement le titre et la description publics, mais aussi une métadonnée `prix_negociation_min`, un champ interne destiné uniquement aux commerciaux, jamais affiché sur le site public.

Ce n'est pas un bug isolé de ce projet : c'est un piège structurel de l'API REST de WordPress, qui mérite une vérification systématique avant toute mise en production, plutôt qu'une découverte a posteriori comme celle-ci.

## Pourquoi show_in_rest expose plus qu'on ne l'imagine

Activer `show_in_rest` sur un type de contenu personnalisé, via `register_post_type()`, l'expose par défaut en lecture publique à travers l'API REST — c'est-à-dire sans authentification requise — exactement comme les articles et pages standards de WordPress le sont déjà. Ce comportement est cohérent avec l'intention générale de `show_in_rest`, mais il est souvent activé sans que l'équipe ait explicitement passé en revue chaque champ personnalisé associé.

Le piège se niche particulièrement dans les métadonnées enregistrées avec `register_post_type_support` ou `register_meta()` : chaque métadonnée doit individuellement déclarer si elle est exposée via REST, avec son propre argument `show_in_rest`, indépendant de celui du type de contenu parent. Une métadonnée créée par un plugin tiers ou par du code plus ancien du site, sans que cet argument ait été pensé au moment de sa création, peut se retrouver exposée par défaut si une évolution ultérieure du code ou une mise à jour de plugin change ce comportement implicite.

## La checklist avant d'activer show_in_rest sur un contenu personnalisé

> L'essentiel à retenir : show_in_rest expose plus que le contenu public par défaut ; Les métadonnées suivent des règles d'exposition séparées ; Une checklist avant mise en ligne évite la découverte a posteriori

1. **Lister exhaustivement les métadonnées associées au type de contenu**, avant même de toucher au code, avec `wp post meta list <ID>` pour un exemple représentatif du contenu concerné. Toute métadonnée non documentée mérite une clarification sur son usage réel avant de décider de son exposition.
2. **Vérifier explicitement l'argument `show_in_rest` de chaque `register_meta()`** plutôt que de laisser la valeur par défaut faire le choix à votre place :
`register_meta( 'post', 'prix_negociation_min', array(
    'object_subtype' => 'bien_immobilier',
    'type'           => 'number',
    'single'         => true,
    'show_in_rest'   => false, // Explicite : jamais exposé publiquement
) );`
3. **Contrôler la fonction `auth_callback` pour les métadonnées qui doivent rester lisibles, mais uniquement par un utilisateur autorisé**, plutôt que de choisir entre tout public ou rien :
`register_meta( 'post', 'contact_commercial_interne', array(
    'object_subtype' => 'bien_immobilier',
    'type'           => 'string',
    'single'         => true,
    'show_in_rest'   => true,
    'auth_callback'  => function() {
        return current_user_can( 'edit_posts' );
    },
) );`
4. **Tester la route REST sans authentification**, exactement comme le ferait un visiteur non connecté, avant chaque mise en production :
`curl -s "https://exemple.fr/wp-json/wp/v2/bien_immobilier/42" | python3 -m json.tool`
La sortie doit être relue champ par champ, pas seulement survolée : c'est précisément cette étape qui avait été sautée sur ce projet.
5. **Filtrer la réponse REST au niveau global si des champs restent exposés malgré tout**, en dernier recours, via `rest_prepare_{post_type}`, pour retirer explicitement tout champ qui ne devrait jamais quitter le serveur :
`add_filter( 'rest_prepare_bien_immobilier', function( $response, $post, $request ) {
    $donnees = $response->get_data();
    unset( $donnees['meta']['prix_negociation_min'] );
    $response->set_data( $donnees );
    return $response;
}, 10, 3 );`

## Ce que révèle ce cas sur les habitudes de développement

Le champ `prix_negociation_min` avait été ajouté des mois avant l'activation de `show_in_rest` sur le type de contenu, par une autre personne, dans un contexte où l'API REST n'était même pas envisagée. C'est cette dissociation dans le temps entre la création d'une métadonnée et l'exposition ultérieure de son type de contenu parent qui rend ce piège si difficile à anticiper sans checklist formelle : personne n'a de raison de repenser à un champ ajouté un an plus tôt au moment d'activer une fonctionnalité qui semble, à première vue, sans rapport.

C'est précisément pour cette raison que la vérification doit être un réflexe systématique déclenché par l'activation de `show_in_rest` elle-même, et non une vérification ponctuelle laissée à la mémoire de l'équipe.

> Sur nos projets, toute activation de `show_in_rest` sur un type de contenu existant déclenche désormais automatiquement une revue de l'ensemble de ses métadonnées associées, avant la mise en ligne, jamais après.

## Pour aller plus loin

Cette checklist ne détaille pas le fonctionnement du paramètre `permission_callback` pour les routes REST personnalisées créées avec `register_rest_route()`, un mécanisme différent traité ailleurs, qui contrôle l'accès à des points d'entrée sur mesure plutôt que l'exposition automatique des types de contenu existants. Les deux sujets se recoupent dans leur objectif, mais interviennent à des niveaux distincts de l'API REST de WordPress.
