# La liste de licenciés mineurs exposée par un export mal restreint

> Un bouton d'export destiné aux entraîneurs générait un fichier consultable par n'importe quel compte connecté, mineurs inclus.

- Auteur : Clément Hadrot
- Publié le : 2023-12-04
- Mis à jour le : 2023-12-04
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/liste-licencies-mineurs-export-mal-restreint/

## L’essentiel

- Un export doit vérifier une capacité, pas seulement un statut connecté
- Une donnée sur un mineur exige un contrôle d'accès renforcé, pas standard
- Restreindre la génération du fichier ne suffit pas si son lien reste devinable

214 lignes, dont l'âge, le nom complet, l'adresse postale et le contact d'un représentant légal : c'est le contenu d'un fichier CSV généré depuis l'espace adhérents d'un club sportif régional, disponible en un clic pour tout compte connecté au site, quel que soit son rôle réel au sein du club.

La fonctionnalité, ajoutée pour permettre aux entraîneurs de générer rapidement la liste de leurs groupes avant une compétition, avait été développée comme une extension métier interne. Le bouton d'export apparaissait sur le tableau de bord accessible à tout adhérent connecté, entraîneur ou non.

## Un contrôle d'accès pensé pour un seul rôle, oublié pour les autres

Le code de génération de l'export vérifiait uniquement que l'utilisateur était connecté, via `is_user_logged_in()`, sans distinction supplémentaire de rôle ni de capacité. La fonctionnalité avait été testée exclusivement avec des comptes d'entraîneurs pendant le développement, ce qui a masqué l'absence de restriction jusqu'à ce qu'un parent, adhérent lui aussi au club pour un cours adulte, découvre le bouton sur son propre tableau de bord.

```
function generer_export_licencies() {
    if ( ! is_user_logged_in() ) {
        wp_die( 'Accès refusé.' );
    }
    $licencies = recuperer_tous_licencies_actifs();
    exporter_csv( $licencies );
}
```

Le parent, sans intention malveillante, a signalé le problème directement au club après avoir constaté qu'il pouvait consulter la fiche complète d'enfants dont il n'était pas le représentant légal, dépassant très largement le périmètre de son propre groupe.

## Pourquoi la donnée d'un mineur change l'exigence

Le RGPD n'interdit pas la collecte de données concernant des mineurs dans le cadre légitime d'une inscription sportive, mais impose une vigilance renforcée sur leur traitement, en particulier sur les fonctionnalités de consultation groupée comme un export. Un fichier CSV regroupant plusieurs centaines de mineurs constitue un traitement à risque particulier, qui appelle un contrôle d'accès plus strict qu'un affichage individuel de fiche.

- L'export regroupait l'ensemble des licenciés actifs, sans filtrage par groupe ni par entraîneur assigné.
- Aucune capacité dédiée ne distinguait un entraîneur d'un adhérent ordinaire dans le code de l'extension.
- Le lien de génération de l'export n'apparaissait dans aucun menu réservé, seulement masqué par du CSS côté client.

> L'essentiel à retenir : Un export doit vérifier une capacité, pas seulement un statut connecté ; Une donnée sur un mineur exige un contrôle d'accès renforcé, pas standard ; Restreindre la génération du fichier ne suffit pas si son lien reste devinable

## Corriger par une capacité dédiée, pas par un rôle générique

La correction retenue introduit une capacité personnalisée, attribuée uniquement aux comptes d'entraîneurs validés par le bureau du club, et restreint en plus l'export aux seuls licenciés du ou des groupes que l'entraîneur encadre effectivement.

```
function generer_export_licencies() {
    if ( ! current_user_can( 'exporter_licencies_groupe' ) ) {
        wp_die( 'Accès réservé aux entraîneurs habilités.', 403 );
    }
    $groupes_autorises = get_user_meta( get_current_user_id(), 'groupes_encadres', true );
    $licencies = recuperer_licencies_par_groupes( $groupes_autorises );
    exporter_csv( $licencies );
}

// Attribution de la capacité, réservée au rôle entraîneur validé.
$role = get_role( 'entraineur_valide' );
$role->add_cap( 'exporter_licencies_groupe' );
```

Le masquage par CSS du bouton, présent dans la version d'origine, a également été retiré : dissimuler un élément d'interface ne retire jamais la possibilité d'appeler directement la fonction sous-jacente, seulement la visibilité du bouton qui y mène.

## Vérifier aussi le lien du fichier généré

Un point supplémentaire a été corrigé lors du même audit : le fichier CSV, une fois généré, était déposé dans le dossier uploads sous un nom prévisible, `export-licencies.csv`, réécrit à chaque nouvelle génération. Un adhérent ayant conservé ce lien pouvait continuer à le consulter après coup, indépendamment de tout nouveau contrôle de capacité appliqué au bouton.

| Élément corrigé | Avant | Après |
| --- | --- | --- |
| Contrôle d'accès au déclenchement | Utilisateur connecté | Capacité dédiée entraîneur validé |
| Périmètre de l'export | Tous les licenciés du club | Groupes effectivement encadrés |
| Stockage du fichier généré | Nom fixe dans uploads | Flux généré à la volée, jamais stocké |

> Conseil retenu par le club après cet incident : toute donnée concernant un mineur mérite une question supplémentaire avant chaque mise en production — qui, précisément, doit pouvoir la consulter, et comment le code le vérifie-t-il réellement ?

## Notre verdict

Ce cas ne relève pas d'une négligence isolée mais d'un biais de conception fréquent : construire un contrôle d'accès en pensant au premier usage prévu, sans revérifier son comportement une fois la fonctionnalité rendue accessible à un public plus large. La sensibilité particulière des données concernant des mineurs ne fait qu'accroître le coût d'un tel oubli, sans en changer la nature.
