LFW

Blog · Ce que révèle l'audit gratuit

Votre médiathèque est publique

La médiathèque n'est pas un dossier privé, ni sous WordPress ni ailleurs. Ce que cela signifie pour les brouillons et les dossiers téléversés pour obtenir un lien, pourquoi couper l'API est le mauvais correctif, et comment marquer un fichier privé sans rien casser.

Public par défaut, dans tous les systèmes

Une médiathèque est un dossier sur un serveur web. Téléverser un fichier, c'est le publier. C'est vrai pour WordPress, pour Drupal et pour un site statique ; la seule différence est la facilité avec laquelle on trouve la liste.

Sous WordPress, la liste est à une adresse de distance. L'API REST à /wp-json/wp/v2/media renvoie chaque fichier de la médiathèque à quiconque le demande, sans connexion. La JSON:API de Drupal fait l'équivalent. Ce n'est pas un défaut. La même API alimente l'éditeur de blocs, les galeries, les applications mobiles et les intégrations que votre équipe utilise déjà.

D'où vient la surprise

Les gens transposent à la médiathèque un modèle Dropbox : un dossier privé où l'on dépose un fichier pour en obtenir un lien. La médiathèque se remplit alors de ce qui n'était jamais destiné à être diffusé. Le brouillon trois d'un rapport dont le brouillon quatre est celui de la page. Un dossier du conseil téléversé pour qu'une personne puisse le télécharger. Un rapport prévu pour la semaine prochaine, téléversé aujourd'hui.

Deux faits sont confondus. Un fichier vers lequel aucune page ne fait de lien est non lié, pas privé. Un fichier difficile à trouver est caché, pas privé. L'API liste les deux, et un moteur qui trouve l'adresse indexera les deux.

Pourquoi couper l'API est le mauvais correctif

La réponse tentante est de désactiver l'API REST, ou de masquer le point d'accès des médias. C'est de la sécurité par l'obscurité : on bloque une façon de lister les fichiers pendant que chaque adresse directe continue de fonctionner, et on casse les fonctions de l'éditeur et les intégrations qui dépendent de l'API.

La vraie question n'est pas de savoir si la médiathèque peut être listée. C'est de savoir quels fichiers y sont censés être publics. Une fois cette question réglée fichier par fichier, l'API cesse d'être un problème et redevient de l'infrastructure.

Comment s'y prendre sous WordPress

D'abord, regardez. Ouvrez /wp-json/wp/v2/media?media_type=application sur votre propre site et lisez ce qui revient. C'est la liste qu'un inconnu voit.

Ensuite, décidez fichier par fichier. Les fichiers publics restent. Les brouillons dépassés et tout ce qui n'était jamais destiné à être publié sont supprimés ; une version publiée par rapport. Les fichiers qui doivent exister sans être découvrables sont marqués privés.

Enfin, marquez-les. Nous avons écrit une petite extension exactement pour cela, LFW Private Media : une case Privé sur chaque fichier joint, plus des actions groupées dans la liste des Médias. Un fichier privé disparaît de l'API publique, de la recherche du site, des pages de fichiers joints et des sitemaps, tandis que vos éditeurs continuent de tout voir. Téléchargez-la à LFW.com/dl/lfw-private-media.zip. Si vous préférez voir le mécanisme plutôt que d'installer quoi que ce soit, l'idée entière tient dans un petit fichier :

Afficher le code Masquer le code PHP, 27 lignes
<?php
/**
 * Plugin Name: Private media (minimal)
 * Keeps attachments carrying the meta key _lfw_private out of the public REST API.
 * Editors (anyone who can upload files) still see them.
 */

// The collection: /wp-json/wp/v2/media
add_filter( 'rest_attachment_query', function ( $args ) {
  if ( current_user_can( 'upload_files' ) ) { return $args; }
  $args['meta_query']   = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
  $args['meta_query'][] = array( 'key' => '_lfw_private', 'compare' => 'NOT EXISTS' );
  return $args;
} );

// A single item: /wp-json/wp/v2/media/123
add_filter( 'rest_request_before_callbacks', function ( $response, $handler, $request ) {
  if ( current_user_can( 'upload_files' ) ) { return $response; }
  if ( preg_match( '#^/wp/v2/media/(\d+)$#', $request->get_route(), $m )
       && '1' === get_post_meta( (int) $m[1], '_lfw_private', true ) ) {
    return new WP_Error( 'rest_post_invalid_id', 'Invalid post ID.', array( 'status' => 404 ) );
  }
  return $response;
}, 10, 3 );

// Mark a file private: add the meta key _lfw_private with the value 1.
// With WP-CLI: wp post meta update <attachment-id> _lfw_private 1

Une limite honnête, pour l'une ou l'autre version. Un fichier déjà public à une adresse directe reste accessible à quiconque a cette adresse. Le marquer privé empêche les inconnus de le découvrir. Cela ne met pas le fichier derrière une authentification. Tout ce qui est vraiment confidentiel n'a rien à faire dans le dossier des téléversements ; sa place est derrière un téléchargement à accès contrôlé.

Si vous êtes client

Vous n'avez rien à installer. Ouvrez une demande dans votre portail et nous auditerons la médiathèque avec vous, supprimerons ce qui doit partir, marquerons privé ce qui doit rester et installerons l'extension. C'est une petite tâche dans le cadre du forfait, pas un projet.

Si vous n'êtes pas encore client, l'audit gratuit vous dira combien de fichiers votre site liste aujourd'hui aux inconnus. C'est généralement le moment où le modèle Dropbox prend fin.

À lire ensuite

6 septembre 2026 8 minutes

Les quatre fichiers vers lesquels personne ne fait de lien

Chaque site web porte quatre fichiers texte qu'aucun visiteur ne voit jamais : robots.txt, sitemap.xml, security.txt et llms.txt. Les moteurs de recherche, les scanners de sécurité et les agents d'IA les lisent à chaque visite. Ce qu'est chacun d'eux, qui les lit vraiment, quoi y mettre, et la seule règle qui les garde tous sûrs. Nous avons repris cette liste sur notre propre site cette semaine et trouvé des manques, alors l'audit gratuit les vérifie désormais.

6 septembre 2026 6 minutes

Notre image principale disparaissait sur iPhone. Un bloqueur de publicités la cachait.

Pendant des semaines, l'image principale de trois de nos propres pages disparaissait une seconde et demie sur iPhone, au premier chargement seulement. Rien ne le reproduisait en laboratoire. Un relevé de terrain de cinquante lignes l'a trouvé en trois chargements de page : un bloqueur de publicités masquait tout élément dont la classe commençait par ad-.

Tous les articles →

Prefer to write?

Tell us what needs to work better.

Slow, fragile, hard to edit, missing a workflow. Say it plainly, and you'll get a straight answer, not a ticket number.

You'll get a straight answer, usually the same day.