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

Extensions

Prise de rendez-vous médical : ne pas exposer de données de santé en métadonnées

Un module de rendez-vous pour un cabinet médical ne peut pas stocker le motif de consultation dans wp_postmeta comme n'importe quel champ. Voici comment isoler ces données.

Par WordPress Développement • 24 décembre 2021 • 5 min de lecture • Aucun commentaire
Prise de rendez-vous médical : ne pas exposer de données de santé en métadonnées

Une donnée de santé n’est pas une donnée personnelle comme les autres. Le RGPD la classe parmi les catégories dites « particulières » (article 9), avec un régime de traitement plus strict qu’un simple nom ou une adresse e-mail. Or un module de prise de rendez-vous médical construit à la va-vite, sur la base d’un CPT « rendez-vous » et de quelques champs ACF, finit presque toujours par stocker le motif de consultation, parfois un antécédent, directement dans wp_postmeta.

Le problème n’est pas seulement réglementaire, il est structurel. La table wp_postmeta est interrogeable par n’importe quel code qui dispose d’un accès à la base, y compris une extension tierce mal isolée, un export SQL de sauvegarde envoyé sans précaution à un prestataire, ou une requête WP_Query avec meta_query écrite par un développeur qui ignore la sensibilité du champ. Concevoir l’architecture en amont pour isoler ces données change radicalement le niveau de risque.

Sortir la donnée sensible du modèle de contenu WordPress

Le premier principe consiste à ne jamais faire transiter une donnée de santé par les tables standards de WordPress. Un rendez-vous, en tant qu’événement (date, praticien, statut), peut rester un post ou une entrée dans une table personnalisée légère. Le motif de consultation, en revanche, doit vivre dans une table séparée, avec ses propres règles d’accès :

CREATE TABLE {$wpdb->prefix}rdv_donnees_sante (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  rdv_id BIGINT UNSIGNED NOT NULL,
  motif_chiffre VARBINARY(1024) NOT NULL,
  cree_le DATETIME NOT NULL,
  KEY rdv_id (rdv_id)
) {$charset_collate};

Cette table n’est jamais interrogée par une WP_Query classique et n’apparaît dans aucun export standard de contenu. Elle est accessible uniquement via une classe d’accès dédiée, qui centralise le chiffrement, le déchiffrement et la vérification des permissions avant toute lecture.

Chiffrer au niveau applicatif, pas seulement au niveau disque

Le chiffrement du disque (souvent proposé par l’hébergeur) protège contre le vol physique du serveur, pas contre un accès non autorisé via l’application elle-même. La donnée doit donc être chiffrée avant son insertion en base, avec une clé stockée hors du dépôt de code et hors de la base de données — typiquement une variable d’environnement injectée au niveau du serveur :

L'essentiel à retenir : Les données de santé sont une catégorie particulière au RGPD ; wp_postmeta n'est jamais le bon endroit pour ce type de donnée ; Chiffrement, capacités dédiées et journal d'accès sont nécessaires
  • Chiffrement symétrique (libsodium, disponible nativement depuis PHP 7.2) plutôt qu’un simple encodage réversible.
  • Clé stockée dans une variable d’environnement, jamais dans wp-config.php versionné.
  • Rotation de clé documentée, même si elle n’est pas mise en œuvre dès le premier déploiement.

Restreindre l’accès avec des capacités dédiées

Un rôle « administrateur » WordPress standard ne devrait pas avoir automatiquement accès au motif de consultation. Il faut créer une capacité spécifique, attribuée uniquement au rôle « praticien » ou « secrétariat médical », et vérifier cette capacité à chaque point d’entrée qui touche à la donnée sensible :

add_action( 'init', function () {
    $role = get_role( 'praticien' );
    if ( $role ) {
        $role->add_cap( 'lire_motif_consultation' );
    }
} );

function rdv_get_motif( int $rdv_id ) {
    if ( ! current_user_can( 'lire_motif_consultation' ) ) {
        return new WP_Error( 'acces_refuse', 'Accès non autorisé à cette donnée.' );
    }
    // Déchiffrement et retour de la donnée.
}

Journaliser chaque accès à la donnée sensible

Au-delà du contrôle d’accès, une exigence souvent oubliée est la traçabilité : qui a consulté quel motif, à quel moment. Un journal d’accès minimal, dans une table distincte, permet de répondre à une demande d’audit ou à une suspicion de fuite sans avoir à fouiller dans les logs serveur bruts :

ColonneRôle
utilisateur_idQui a consulté la donnée
rdv_idQuel rendez-vous concerné
horodatageQuand l’accès a eu lieu

Ce que l’extension ne doit pas gérer elle-même

Il est tentant, une fois cette architecture posée, de vouloir aussi gérer l’hébergement conforme HDS (hébergement de données de santé) directement depuis l’extension. Ce n’est pas son rôle : l’hébergement HDS est une certification qui concerne l’infrastructure entière, pas un module applicatif. L’extension doit être conçue pour fonctionner correctement sur un hébergement HDS, sans jamais prétendre en tenir lieu.

Un module qui manipule une donnée de santé sans que son architecture ait été pensée pour l’isolement dès le départ n’est pas un module qu’on corrige à la marge : c’est un module qu’on reconstruit.

Notre verdict

Un module de prise de rendez-vous médical n’est jamais un simple CPT avec des champs ACF. La donnée sensible — le motif de consultation, un antécédent, une pièce jointe médicale — doit être isolée dans une table dédiée, chiffrée au niveau applicatif, protégée par des capacités spécifiques et journalisée à chaque accès. Cette rigueur architecturale coûte plus cher en développement initial, mais elle est la condition sine qua non pour livrer un module réellement adapté au secteur santé.

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