# Un espace membre headless exposait les commandes WooCommerce d’un autre client

> Un audit de sécurité a révélé qu'un front découplé permettait de consulter l'historique de commandes d'un autre client, faute de vérification correcte de l'identité côté Store API.

- Auteur : Clément Hadrot
- Publié le : 2023-10-22
- Mis à jour le : 2023-10-22
- Catégorie : Headless &amp; API
- URL : https://wpmoderne.dev.wordpress-developpement.fr/headless/faille-store-api-woocommerce-commandes-autre-client/

## L’essentiel

- Le jeton de panier n'était pas lié de façon fiable à l'identité du client connecté
- Un identifiant de commande prévisible suffisait à consulter une commande tierce
- Le correctif a demandé de revalider systématiquement la propriété de la ressource

Un audit de sécurité de routine, mené avant la période de forte activité de fin d'année sur une boutique de vêtements techniques, a mis au jour une faille sérieuse : en modifiant simplement un identifiant numérique dans l'URL d'une requête vers la Store API de WooCommerce, il était possible de consulter les détails complets d'une commande appartenant à un autre client, nom, adresse de livraison et articles commandés compris. Ce cas ne traite pas de la sécurité générale du panier headless dans son ensemble, un sujet plus large déjà abordé ailleurs sur ce blog, mais spécifiquement de cette faille précise et de son correctif.

## Le contexte du projet audité

Le front, développé en Nuxt, consommait la Store API native de WooCommerce pour tout le parcours d'achat, du panier jusqu'à la page de suivi de commande, accessible depuis l'espace membre du site. Cette page de suivi appelait un point de terminaison du type `/wp-json/wc/store/v1/order/{id}`, avec l'identifiant de commande transmis directement en paramètre d'URL depuis le lien présent dans l'historique de commandes du visiteur connecté.

## Comment la faille a été découverte

L'auditeur, en testant simplement l'incrémentation manuelle de l'identifiant de commande dans l'URL d'une commande légitimement consultable depuis son propre compte de test, a obtenu sans encombre les détails d'une commande appartenant à un identifiant de compte différent :

```
GET /wp-json/wc/store/v1/order/1042
Cookie: woocommerce_cart_hash=abc123...

# Réponse obtenue, alors que la commande 1042
# appartenait à un compte client totalement différent :
{
  "id": 1042,
  "billing_address": {
    "first_name": "Camille",
    "last_name": "Rousseau",
    "address_1": "14 rue des Tilleuls"
  },
  "line_items": [ ... ]
}
```

La Store API de WooCommerce vérifiait bien la présence d'un jeton de panier valide (`Cart-Token`), mais ne confirmait pas que ce jeton de panier appartenait effectivement au propriétaire réel de la commande demandée : elle vérifiait qu'une session existait, pas qu'elle correspondait à la bonne personne pour cette ressource précise.

> L'essentiel à retenir : Le jeton de panier n'était pas lié de façon fiable à l'identité du client connecté ; Un identifiant de commande prévisible suffisait à consulter une commande tierce ; Le correctif a demandé de revalider systématiquement la propriété de la ressource

## Le correctif appliqué

Le correctif a consisté à ajouter un filtre côté WordPress, intercepté avant que la réponse ne parte, pour vérifier explicitement que l'identifiant client associé à la commande demandée correspond bien à l'utilisateur authentifié effectuant la requête :

```
add_filter( 'woocommerce_store_api_disable_nonce_check', '__return_false' );

add_action( 'woocommerce_store_api_order_data_response', function ( $response, $request ) {
    $order_id = $request->get_param( 'id' );
    $order    = wc_get_order( $order_id );

    if ( ! $order ) {
        return;
    }

    $utilisateur_courant = get_current_user_id();

    if ( (int) $order->get_customer_id() !== (int) $utilisateur_courant ) {
        wp_send_json_error(
            array( 'message' => 'Accès non autorisé à cette commande' ),
            403
        );
    }
}, 10, 2 );
```

Cette vérification confirme que la commande demandée appartient bien à l'utilisateur authentifié à l'origine de la requête, indépendamment de la validité générale du jeton de panier utilisé. Une commande passée en tant qu'invité, sans compte associé, a nécessité un traitement complémentaire, en s'appuyant sur la correspondance entre le jeton de panier ayant servi à la commande et celui de la session courante, plutôt que sur un identifiant de compte inexistant dans ce cas.

## Vérifier que le correctif tient réellement

- Reproduction systématique du scénario d'origine : tentative d'accès à une commande d'un autre compte, avec confirmation d'un refus explicite en `403`.
- Test du parcours invité, sans compte, pour s'assurer que le correctif ne bloque pas un client légitime n'ayant jamais créé de compte.
- Revue de tous les autres points de terminaison de la Store API manipulant un identifiant de commande, pour vérifier qu'aucun autre chemin ne contourne la même vérification.

## Ce que cet incident a changé dans notre méthode d'audit

Depuis ce projet, tout audit de sécurité sur un espace membre headless inclut systématiquement un test de contrôle d'accès horizontal : la simple modification d'un identifiant numérique dans une requête légitime, pour vérifier qu'une ressource appartenant à un autre utilisateur reste bien inaccessible. C'est un test simple, rapide à exécuter, et pourtant capable de révéler des failles bien plus graves que la plupart des vérifications automatisées classiques.

> Une authentification valide ne garantit jamais, à elle seule, le droit d'accéder à une ressource précise : chaque ressource sensible doit vérifier explicitement qu'elle appartient bien à la personne qui la demande.

## En résumé

Cette faille n'avait rien d'exotique ni de sophistiqué : un simple identifiant numérique prévisible, combiné à une vérification d'authentification incomplète, suffisait à exposer les données personnelles de plusieurs clients. Le correctif, une fonction de quelques lignes vérifiant la propriété réelle de la ressource, illustre une règle qui vaut pour toute API headless : vérifier qu'un visiteur est connecté ne dit jamais s'il a le droit de voir ce qu'il demande précisément.
