Thought leaders

Je MCP-server is veilig. Het grootboek erachter niet.

mm
Voeg Unite.AI toe aan je voorkeursbronnen op Google

In een recent artikel hier op Unite.AI zette Gil Feig zes best practices voor het bouwen van een veilige MCP-server uiteen. Die zijn goed onderbouwd, en iedereen die een MCP-server uitbrengt, zou ze moeten volgen. Zijn advies om elke integratie „een eigen, fijnmazige rol te geven, strikt beperkt tot de vereiste machtigingen” is precies raak. Het gaat er ook van uit dat het systeem aan de andere kant fijnmazige rollen ondersteunt. Daarachter schuilt een bredere aanname die zelden wordt uitgesproken: dat de systemen achter de server volgens dezelfde norm kunnen worden beveiligd.

In bedrijfssoftware is dat vaak niet mogelijk. Ik leid het engineeringteam achter een integratielaag die verbinding maakt met 32 boekhoud- en ERP-systemen, met daarbovenop een optionele MCP-server. We zien regelmatig dat agents aan onze kant goed zijn geauthenticeerd, dat hun toegang goed is afgebakend en dat hun activiteiten goed worden gelogd, terwijl ze gegevens wegschrijven naar systemen die niet eens kunnen vaststellen dat er een agent bij betrokken was.

Dit artikel gaat over de tweede helft van het probleem: wat de upstreamsystemen daadwerkelijk bieden, wat je vanuit de integratielaag kunt beheersen en waar die controle ophoudt.

Waar de MCP-specificatie de controle overdraagt

De MCP-autorisatiespecificatie is duidelijk over haar eigen grenzen. De MCP-server is een OAuth-resourceserver voor zijn clients. Wanneer de server een upstream-API aanroept, treedt hij op als een afzonderlijke OAuth-client, met een apart token dat door het upstreamsysteem is uitgegeven. Het token van de client doorgeven is uitdrukkelijk verboden.

Dat is het juiste ontwerp. Het betekent ook dat alles rond de upstream-aanroep, waaronder wie wat mag doen en hoe dat wordt vastgelegd, volledig afhangt van het upstreamsysteem. De specificatie kan niet oplossen wat het upstreamsysteem niet biedt.

Hetzelfde geldt voor de OWASP-richtlijnen voor buitensporige autonomie. Daarin wordt aanbevolen de machtigingen die de uitbreidingen van een agent in andere systemen hebben, te beperken tot het noodzakelijke minimum en acties uit te voeren in de context van de gebruiker namens wie de agent handelt. Beide adviezen zijn goed. Beide gaan ervan uit dat het andere systeem een manier biedt om minimale machtigingen en de gebruikerscontext vast te leggen.

Wat upstreamsystemen daadwerkelijk bieden

Zo zien de 32 boekhoud- en ERP-systemen waarmee we verbinding maken eruit vanuit het perspectief van een integrator.

Een derde heeft helemaal geen OAuth

21 van de 32 systemen gebruiken OAuth. De overige 11 werken met statische inloggegevens: API-sleutels, een gebruikersnaam en wachtwoord, of een combinatie van twee tokens. Sommige van die sleutels verlopen nooit. In de documentatie van één veelgebruikt systeem staat dat de API-tokens onbeperkt geldig blijven zolang de gebruiker bestaat.

Lange geldigheid, weinig mogelijkheden tot intrekking

OAuth biedt minder bescherming dan je zou hopen. Eén provider geeft refresh-tokens uit met een geldigheidsduur van ongeveer 20 jaar. Dat is een inloggegeven dat is ontworpen om langer mee te gaan dan de agent die het gebruikt, het framework waarop die agent is gebouwd en mogelijk zelfs de persoon die op ‘toestaan’ klikte. In een ander systeem verlopen zelfs de access-tokens niet.

En zodra een inloggegeven is uitgegeven, is de vraag wie het kan uitschakelen. De standaard daarvoor, het intrekken van OAuth-tokens (RFC 7009), bestaat al sinds 2013. Toch bieden ongeveer vier op de tien systemen een integrator geen technische mogelijkheid om inloggegevens in te trekken. Alle systemen die met API-sleutels werken, vallen in die groep. De enige resterende mogelijkheid is de klant te vragen de toegang handmatig te verwijderen.

Beperkte scopes, geen agentidentiteit

De meeste statische sleutels erven simpelweg alle rechten van de gebruiker die ze heeft aangemaakt; slechts bij enkele systemen kun je een sleutel beperken tot afzonderlijke eindpunten. Veel OAuth-systemen hebben scopes, maar die zijn doorgaans grofmazig, bijvoorbeeld ‘boekhouding, lezen en schrijven’. En bij geen van de 32 systemen konden we een manier vinden om via de API bij dezelfde transactie zowel de agent als de persoon namens wie die handelt vast te leggen. Externe agents verschijnen óf als de gebruiker die ze heeft gekoppeld, óf als een generieke systeemgebruiker. Veelzeggend is dat een leverancier die agents in zijn eigen product heeft ingebouwd, zoals Microsoft in Business Central, daarvoor speciale gebruikersaccounts heeft aangemaakt. Dat is hetzelfde patroon dat ik hieronder aanbeveel, maar dan uitsluitend voor de eigen agents van de leverancier.

Wat de integratielaag kan afdwingen

Dit betekent niet dat je de handdoek in de ring moet gooien. Tussen de agent en het boekhoudsysteem heb je vrijwel alles zelf in de hand:

  • inloggegevens per agent voor je eigen laag
  • je eigen scopes, bijvoorbeeld alleen-lezen toegang tot facturen
  • een auditlog van elke aanroep door een agent, inclusief de persoon namens wie die handelde
  • idempotentiesleutels, zodat een agent die een verzoek opnieuw probeert niet dezelfde factuur twee keer boekt
  • frequentielimieten per agent
  • goedkeuringsstappen voordat er iets wordt weggeschreven

Niets daarvan hangt af van wat het doelsysteem ondersteunt. Een krachtige toegangslaag op integratieniveau is vandaag al mogelijk, en als je agents in de buurt van financiële gegevens laat komen, moet je er een bouwen.

Waar het ophoudt

Wat je niet kunt doen, is die laag uitbreiden tot voorbij de systeemgrens. Daar gaat het op drie punten mis.

Herleidbaarheid

Binnen het boekhoudsysteem verschijnt de boeking van de agent onder de naam van degene die de verbinding heeft geautoriseerd, of onder die van een technische gebruiker. Iedereen die het systeem controleert, ziet een boeking van die gebruiker. Ze kunnen niet zien of een persoon of een agent die heeft gedaan. Voor het grootboek ziet een agent die om 3.00 uur 400 facturen boekt er precies hetzelfde uit als een zeer ijverige financieel manager. Om te achterhalen wat er is gebeurd, zijn de logboeken van de integrator nodig. Dat is een andere vertrouwensketen dan die van het registratiesysteem. Voor forensisch onderzoek of een audit is dat een zwakke positie.

De meeste organisaties lopen hierin ook niet voorop. In een enquête van de Cloud Security Alliance zei slechts 28% van de respondenten dat ze agentacties in alle omgevingen betrouwbaar konden herleiden tot een persoon of systeem, en 44% gebruikt of is van plan statische API-sleutels voor hun agents te gebruiken.

Minimale toegangsrechten

Je kunt afdwingen dat een agent alleen facturen leest. Maar als het doelsysteem geen scopes heeft, bieden de inloggegevens achter je laag nog steeds volledige toegang. Iedereen die ze in handen krijgt, kan je laag en alle regels die je ermee hebt opgesteld volledig omzeilen.

Intrekking

Je kunt je eigen agent onmiddellijk uitschakelen. Dat helpt niet als de inloggegevens voor het doelsysteem zelf zijn gecompromitteerd. En bij de 4 op de 10 systemen zonder een intrekkingsendpoint bestaat de noodstop uit een e-mail aan de klant.

De praktische oplossing: een aparte gebruikersaccount voor de agent

Het nuttigste wat je vandaag kunt doen, is niet spectaculair. Maak in het doelsysteem een aparte gebruikersaccount voor de agent aan en verbind de agent uitsluitend via die account.

Dit werkt in elk systeem waarin je gebruikers kunt aanmaken en levert drie dingen op die de integratielaag niet kan bieden:

  • Herleidbaarheid in het registratiesysteem. Boekingen verschijnen onder de naam ‘crediteurenagent’, niet onder die van de financieel manager die zes maanden geleden op ‘verbinden’ klikte.
  • Een manier om de toegang in te trekken, zelfs zonder API. De klant kan de gebruiker uitschakelen in de interface. Dat werkt ook in systemen zonder intrekkingsendpoint.
  • Gedeeltelijke toepassing van minimale toegangsrechten. Als het systeem überhaupt rollen ondersteunt, kan de toegang van de agent vaak worden beperkt tot de modules die hij daadwerkelijk nodig heeft.

De kosten zijn reëel. Iemand moet tijdens de onboarding de gebruiker handmatig aanmaken, wat op precies het verkeerde moment extra drempels opwerpt. Ongeveer de helft van de systemen brengt kosten in rekening voor elke extra gebruiker: van een paar euro per maand bij tools voor kleine bedrijven tot meer dan honderd euro per maand bij een volledig ERP-systeem. Bij verschillende andere systemen is het aantal gebruikers per abonnement begrensd, waardoor één extra gebruiker voor het hele bedrijf een duurder abonnement kan betekenen. En een serviceaccount waarvoor niemand verantwoordelijkheid draagt, vormt op zichzelf een risico en draagt bij aan de verspreiding van niet-menselijke identiteiten waar Unite.AI eerder over heeft geschreven. Net als elke andere account heeft ook deze een eigenaar en een datum voor periodieke controle nodig.

Dit lost het ontbreken van scopes in systemen die ze niet hebben ook niet op. Maar het brengt herleidbaarheid en intrekking terug naar het systeem waar auditors daadwerkelijk kijken.

De structurele oplossing: gedelegeerde identiteit

De juiste oplossing bestaat op papier al. OAuth 2.0-tokenuitwisseling (RFC 8693) maakt onderscheid tussen impersonatie en delegatie. Bij delegatie behoudt de agent zijn eigen identiteit en legt het token via de claim ‘act’ vast dat de agent namens een persoon handelt.

Toegepast op de boekhouding zou dat betekenen:

  • in het grootboek wordt vastgelegd dat deze agent deze boeking namens deze persoon heeft gedaan
  • scopes worden per delegatie toegekend, niet per gebruiker
  • een afzonderlijke delegatie kan worden ingetrokken zonder de account van de persoon te wijzigen

Voor zover ik heb kunnen nagaan, ondersteunt geen van de 32 systemen iets wat hierop lijkt. Voorlopig blijft dit dus een richting, geen optie. Daarom is dit een verzoek aan aanbieders van boekhoud- en ERP-software, en geen taak voor integrators: agents schrijven al naar je grootboeken en je API’s zouden dat moeten kunnen aangeven.

Wat je moet doen voordat een agent toegang krijgt tot een grootboek

Als je agents koppelt aan boekhoud- of ERP-systemen, houd dan deze korte checklist aan:

  1. Breng het model voor inloggegevens van elk doelsysteem in kaart. Is het OAuth of een statische sleutel? Hoelang blijft de inloggegeven geldig? Zijn er scopes en kun je de toegang intrekken?
  2. Richt hoe dan ook je eigen toegangslaag in. Identiteit per agent, scopes, idempotentie en goedkeuringen horen aan jouw kant thuis, ongeacht wat het doelsysteem biedt.
  3. Gebruik waar mogelijk een aparte gebruikersaccount voor de agent. Accepteer de extra inspanning bij de onboarding en de licentiekosten als de prijs voor herleidbaarheid.
  4. Zorg dat je eigen audittrail manipulatiebestendig is. Voor veel systemen is dit het enige bewijs dat er een agent bij betrokken was.
  5. Leg het restrisico vast. Als een systeem geen scopes en geen mogelijkheid tot intrekking heeft, meld dat dan aan uw klant en neem het op in uw eigen risicoregister.

De grens is waar het om draait

Het beveiligen van uw MCP-server is noodzakelijk. Het is niet voldoende. De beveiliging van een agent die naar een grootboek schrijft, wordt bepaald op de grens tussen uw laag en het bronsysteem. Op dit moment wordt die grens bepaald door de systemen, niet door u.

Het goede nieuws is dat de tekortkomingen duidelijk zijn afgebakend. De standaarden bestaan. Wat ontbreekt, is ondersteuning daarvoor in de systemen waarin de boekhouding wordt bijgehouden.

Lennart Svensson is CTO bij maesn, waar hij de integratielaag ontwikkelt die software verbindt met meer dan 30 boekhoud- en ERP-systemen. Eerder werkte hij als architect en software-engineer bij grote bedrijven in Europa.