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

Extensions

Un dépôt sécurisé de justificatifs pour un cabinet d’expertise comptable

Un espace d'upload restreint par capacité personnalisée évite d'exposer les documents d'un client à un autre, sans complexité d'extranet dédié.

Par WordPress Développement • 17 août 2023 • 4 min de lecture • Aucun commentaire
Un dépôt sécurisé de justificatifs pour un cabinet d'expertise comptable

Un expert-comptable indépendant, qui accompagne une vingtaine de PME locales, avait un besoin précis : que chaque client dépose ses relevés bancaires et factures directement depuis son espace WordPress, sans passer par des pièces jointes e-mail dispersées, tout en étant certain qu’un client ne puisse jamais accéder, même par erreur d’URL, aux documents d’un autre client.

La solution retenue n’a pas nécessité un extranet complexe avec système de comptes tiers : WordPress fournit déjà, via son système de rôles et de capacités personnalisées, tout ce qu’il faut pour construire cette isolation, à condition de ne pas se contenter du système de rôles par défaut.

Le piège du dossier uploads standard

La première tentation, la plus rapide à développer, consiste à utiliser le système de médias natif de WordPress : chaque client dépose son fichier via un champ d’upload standard, qui atterrit dans wp-content/uploads/. Ce dossier, servi directement par le serveur web sans passer par PHP, rend chaque fichier accessible par son URL directe à quiconque la devine ou la trouve indexée, indépendamment de toute vérification de connexion ou de rôle.

Pour des documents comptables, cette exposition est inacceptable, même si l’URL contient un nom de fichier peu prévisible : un identifiant devinable ou une fuite accidentelle de lien suffirait à exposer les relevés bancaires d’un client à toute personne extérieure.

Une capacité personnalisée par espace client

L'essentiel à retenir : Une capacité personnalisée isole chaque client de son propre espace ; Le contrôle d'accès se vérifie au moment du téléchargement, pas seulement à l'affichage ; Les fichiers sortent du dossier uploads public par défaut

La structure retenue attribue à chaque compte client un rôle dédié, porteur d’une capacité personnalisée qui encode l’identifiant du cabinet virtuel auquel il appartient, via une métadonnée utilisateur plutôt qu’un rôle distinct par client, ce qui resterait ingérable à vingt-quatre clients et plus.

add_action( 'init', function () {
    $role = get_role( 'client_cabinet' );
    if ( $role && ! $role->has_cap( 'deposer_justificatif' ) ) {
        $role->add_cap( 'deposer_justificatif' );
    }
} );

function cabinet_utilisateur_peut_acceder_dossier( int $user_id, int $dossier_id ): bool {
    if ( ! user_can( $user_id, 'deposer_justificatif' ) ) {
        return false;
    }

    $dossier_proprietaire = get_post_meta( $dossier_id, 'client_id', true );

    return (int) $dossier_proprietaire === $user_id;
}

Chaque document déposé est enregistré comme un article d’un type de contenu personnalisé justificatif, avec une métadonnée client_id qui porte l’identifiant du client propriétaire. La capacité deposer_justificatif autorise le dépôt, mais l’accès à un document précis passe systématiquement par une vérification supplémentaire de propriété, indépendante du rôle.

Servir les fichiers hors du dossier public

Les fichiers eux-mêmes ne sont jamais stockés dans le dossier uploads standard, mais dans un répertoire séparé, en dehors de la racine web accessible directement, ou protégé par une règle de serveur qui bloque l’accès direct. Le téléchargement passe systématiquement par un script PHP qui vérifie la propriété avant de servir le fichier :

add_action( 'template_redirect', function () {
    if ( ! isset( $_GET['telecharger_justificatif'] ) ) {
        return;
    }

    $dossier_id = absint( $_GET['telecharger_justificatif'] );
    $user_id    = get_current_user_id();

    if ( ! cabinet_utilisateur_peut_acceder_dossier( $user_id, $dossier_id ) ) {
        wp_die( 'Accès refusé.', 403 );
    }

    $chemin = get_post_meta( $dossier_id, 'chemin_fichier', true );

    if ( ! $chemin || ! file_exists( $chemin ) ) {
        wp_die( 'Document introuvable.', 404 );
    }

    header( 'Content-Type: application/pdf' );
    header( 'Content-Disposition: attachment; filename="justificatif.pdf"' );
    readfile( $chemin );
    exit;
} );

Ce script ne fait confiance à aucune information transmise par le navigateur pour établir l’accès : il revérifie systématiquement, à chaque téléchargement, la relation entre l’utilisateur connecté et le document demandé, indépendamment de ce qu’affichait l’écran précédent.

Points de vigilance retenus

  • Ne jamais faire confiance à l’affichage de l’interface pour la sécurité : un lien masqué dans le CSS reste accessible directement par son URL.
  • Vérifier la propriété du document à chaque téléchargement, pas seulement lors de la génération de la liste des documents visibles.
  • Interdire l’indexation du dossier de stockage par le serveur web, en complément de la vérification applicative.

Le principe que j’applique sur tout espace de dépôt de documents sensibles : la vérification d’accès doit se refaire au moment précis du téléchargement, jamais seulement au moment où le lien a été affiché à l’écran.

En résumé

Une capacité personnalisée combinée à une vérification de propriété au moment du téléchargement suffit à construire un espace de dépôt cloisonné entre clients, sans extranet dédié ni système de comptes tiers. La comptabilité elle-même, tenue par le cabinet dans son propre logiciel métier, reste en dehors du périmètre de cette extension.

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