Sécuriser la nouvelle surface d'attaque : l'autorisation pour les agents utilisateurs d'outils et MCP

Emmanuel Gautier Emmanuel Gautier ·
Sécurité des outils

Cet article fait partie de la série Les défis d’authentification et d’autorisation de l’IA agentique.

Donner un outil à un agent semble être une petite décision — une définition de fonction, quelques paramètres, une chaîne de description que le modèle lit pour décider quand l’appeler. Du point de vue de l’autorisation, ce n’est pas une petite décision du tout : vous venez de mettre en place un nouveau client API, avec tout ce que cela implique en matière de qui est autorisé à l’appeler, ce qu’il est autorisé à faire, et comment vous sauriez s’il était détourné. Un nombre frappant de déploiements d’agents en phase initiale sautent complètement cette étape, sous prétexte qu’un appel d’outil serait d’une certaine façon différent d’un appel d’API. Ce n’est pas le cas. C’est la faille de surface d’outils.

« Ce n’est qu’un appel d’outil » est tout le problème

Le Model Context Protocol (MCP) et les standards d’appel d’outils similaires ont rendu considérablement plus simple la connexion d’agents à des sources de données et services externes — c’est précisément leur raison d’être, et c’est réellement utile. Mais « plus simple à connecter » et « correctement autorisé » sont deux propriétés différentes, et c’est dans l’écart entre les deux que se situe la véritable exposition. Un serveur MCP, ou tout endpoint d’outil équivalent, sans authentification devant lui est joignable par n’importe quel agent qui le découvre — aucune vérification d’identité, aucune vérification de permission, aucune trace de qui l’a appelé ni pourquoi. Et les actions que ces outils réalisent sont rarement en lecture seule : les agents construits par-dessus exécutent des transactions, modifient des enregistrements et déclenchent des workflows, ce qui signifie qu’un endpoint d’outil non authentifié n’est pas une curiosité, c’est une porte ouverte avec de vraies conséquences de l’autre côté.

L’instinct de traiter cela comme moins critique qu’une « vraie » API est compréhensible mais à contresens. Un outil qu’un agent peut appeler de façon autonome, sur la base de son propre raisonnement quant au moment de l’invoquer, mérite davantage de rigueur d’autorisation qu’un client API opéré par un humain, pas moins — il n’y a personne dans la boucle pour vérifier que l’appel a du sens avant qu’il ne parte.

La couche protocolaire : OAuth 2.1 plus les extensions de découverte et de scoping

Les standards modernes d’appel d’outils convergent vers OAuth 2.1 comme socle — lequel, notamment, impose PKCE pour chaque flux authorization code et abandonne entièrement l’implicit grant, fermant certains des patterns les plus faibles qui ont persisté dans les déploiements OAuth 2.0 pendant des années. Par-dessus ce socle, une poignée d’extensions résolvent les problèmes précis de découverte et de scoping qui apparaissent dès qu’on a de nombreux serveurs d’outils et de nombreux clients agents, plutôt qu’une seule application et une seule API :

Authorization Server Metadata (RFC 8414) et son équivalent côté resource server, Protected Resource Metadata (RFC 9728), permettent à un serveur d’outils de publier, à un endpoint bien connu, quel authorization server le protège et ce qu’il attend des tokens entrants — de sorte qu’un client agent puisse découvrir le bon endroit où demander l’accès sans configuration codée en dur et maintenue manuellement pour chaque outil.

Dynamic Client Registration (RFC 7591), et des alternatives plus légères construites sur la même idée, permettent à un client agent de s’enregistrer lui-même auprès d’un authorization server de façon programmatique, plutôt que d’exiger qu’un humain provisionne manuellement des credentials pour chaque nouvelle instance d’agent en amont. Cela compte particulièrement parce que les flottes d’agents ont tendance à croître plus vite que les workflows de provisionnement manuel de clients ne peuvent suivre — si l’enregistrement d’une nouvelle instance d’agent nécessite un ticket auprès d’une équipe plateforme, soit le processus devient un goulot d’étranglement, soit, plus probablement, les équipes commencent à réutiliser un même enregistrement client partagé entre des agents qui ne devraient pas le partager.

Resource Indicators (RFC 8707) permettent à un client de déclarer explicitement, au moment de la requête, à quel resource server précis un token est destiné — remplaçant l’ambiguïté d’une audience générique par une déclaration explicite, par requête. Plusieurs standards d’appel d’outils s’appuient sur des identifiants de ressource exactement de cette façon, de sorte qu’un token émis pour un serveur d’outil ne puisse pas être discrètement réutilisé contre un autre qu’il n’était jamais censé atteindre.

Rien de tout cela n’est exotique ; c’est la même mécanique de découverte, d’enregistrement et de scoping d’audience dont les déploiements OAuth ont besoin depuis des années, appliquée à un monde où le nombre de « resource servers » (les outils) et de « clients » (les agents) est un ordre de grandeur plus élevé et bien plus dynamique que ce qu’une application web typique a jamais eu à gérer.

Schéma de la faille de surface d'outils : le nœud agent et le nœud outil/API interne du modèle de confiance de l'IA agentique, reliés par une flèche mettant en évidence la faille 5, surface d'outils

L’authentification n’est pas la même question que l’autorisation

Une nuance qui mérite d’être énoncée explicitement, car il est facile de considérer le problème résolu dès qu’un serveur d’outil vérifie la validité d’un token : prouver quel agent appelle (authentification) est une question différente de prouver que cet appel précis est permis (autorisation), et un endpoint d’outil a besoin des deux. Un agent valablement authentifié présentant un token légitime n’est pas pour autant automatiquement habilité à invoquer chaque action exposée par le serveur d’outil — le même scoping en moindre privilège évoqué tout au long de cette série s’applique au niveau de chaque action d’outil individuelle, pas seulement au niveau de « ce client est-il reconnu ».

C’est aussi ici que réapparaît le pattern on-behalf-of vu plus tôt dans cette série : si un serveur d’outil, ayant authentifié l’agent appelant, doit ensuite appeler une autre API interne pour le compte de l’utilisateur d’origine, c’est un nouveau saut de délégation, et il mérite un nouveau token exchange, précisément scopé, plutôt qu’une simple transmission du credential présenté par l’agent. Les serveurs d’outils qui sautent cette étape et transmettent tel quel le token de l’agent à tout ce qui suit en aval réintroduisent l’anti-pattern du token pass-through, un niveau plus loin de l’endroit où on le discute habituellement.

Recommandations de conception

Traitez chaque outil et chaque serveur d’appel d’outils comme une API de production, sans exception informelle. « C’est purement interne » ou « ce n’est qu’un wrapper autour d’un endpoint en lecture seule » sont les deux justifications qui précèdent le plus souvent un incident. Si un système peut être appelé par un agent autonome, il a besoin de la même rigueur d’authentification et d’autorisation que n’importe quel système qu’un humain pourrait appeler directement — sans doute davantage, étant donné l’absence d’un humain qui vérifierait la cohérence de chaque appel.

Utilisez l’enregistrement dynamique ou un mécanisme d’onboarding léger équivalent, pas un provisionnement manuel de credentials, dès que vous dépassez une poignée d’instances d’agent. Dès que l’enregistrement d’un nouvel agent exige qu’une personne crée et transmette manuellement un client secret, vous avez construit un processus qui finira par être contourné — généralement en partageant des credentials entre des agents qui devraient chacun avoir les leurs.

Scopez explicitement les tokens au serveur d’outil ou à la ressource précise appelée, pas à une audience large qui se trouve la couvrir. Les resource indicators existent précisément pour qu’un token émis pour un outil ne puisse pas être rejoué contre un autre. Si vos tokens ne portent pas aujourd’hui ce type de liaison explicite, c’est une faille qu’il vaut la peine de combler avant qu’elle ne soit découverte par quelqu’un d’autre que vous.

Ne confondez pas « cet agent est bien celui qu’il prétend être » avec « cet agent est autorisé à faire ceci ». L’authentification répond à la première question. Elle ne dit rien de la seconde. Chaque action d’outil qui compte a besoin de sa propre vérification d’autorisation, informée par le scope accordé à l’agent pour cette tâche précise — pas seulement d’un pass/fail sur la validité du token.

Quand un serveur d’outil doit lui-même accéder à des systèmes plus loin dans la chaîne, redéléguez plutôt que de transmettre. Un serveur d’outil placé entre un agent et une API interne est lui-même désormais un maillon d’une chaîne de délégation, et il devrait se comporter comme tel : échanger contre un token fraîchement scopé lors d’un appel plus loin, plutôt que d’agir comme un tuyau transparent pour le token qu’il a reçu.

Confier un outil à un agent, c’est lui confier la capacité d’agir — traiter la connexion à la légère parce qu’elle est présentée comme « juste un appel d’outil » est exactement la façon dont la faille de surface d’outils se transforme en l’incident qui rend la revue de sécurité du trimestre suivant considérablement moins agréable.

Prochain article de la série : Le moindre privilège au niveau des données : l’autorisation relationnelle pour le RAG, qui traite de la question à laquelle les scopes au niveau des outils ne peuvent pas répondre seuls : non pas seulement cet agent peut-il appeler cette API, mais peut-il récupérer cet enregistrement précis, pour cet utilisateur précis, maintenant.