Security by design: autorisatie

Geschreven door Rob Dekkers

Autorisatie is een belangrijk mechanisme om de veiligheidsaspecten vertrouwelijkheid en integriteit van de app te kunnen garanderen. Gebruikers mogen alleen inzien en wijzigen waartoe zij gerechtigd zijn. Een Mendix app heeft verschillende mogelijkheden om dat te bereiken. In de vorige blog Security by design: client API hebben we laten zien dat een kwaadwillende gebruiker buiten de schermen om de client API kan gebruiken. Ook hiertegen is autorisatie in Mendix een belangrijk wapen.
In de lijst Web Application Security Risks van OWASP (Open Web Application Security Project) staat Broken Access Control in 2021 op nummer één. En in de lijst Most Dangerous Software Weaknesses van CWE (Common Weaknesses Enumeration) staat Missing Authorization in 2021 op nummer 18. Dus in de praktijk worden veel fouten in de autorisatie van web applications gemaakt.

Mendix autorisatie

In Mendix kan op de volgende manieren autorisatie worden geconfigureerd en geprogrammeerd:

  1. Recht op starten van pages, microflows en nanoflows;
  2. CRUD-rechten op entiteiten en attributen;
  3. Xpath-filter bij het ophalen, wijzigen en verwijderen van entiteiten;
  4. conditionele wijzigbaarheid van attributen op pages;
  5. conditionele zichtbaarheid van attributen op pages;
  6. specifiek geprogrammeerde autorisatie in before event handlers van entiteiten, in micro-/nanoflows en validaties op pages.

De eerste drie kunnen worden toegewezen aan modulerollen die op hun beurt via gebruikersrollen aan de gebruiker (hieronder vallen ook andere systemen als webuser) worden toegekend. De rechten van rollen zijn additief. De client API respecteert deze autorisatierechten volledig. Ook before event handlers worden door de client API gerespecteerd.

Indien Apply entity access van een microflow aanstaat, dan worden de autorisatierechten van de gebruiker gecontroleerd bij elke data-actie in de microflow. Indien uitgezet, dan wordt er niet op autorisatierechten gecontroleerd in de microflow. Deze laatste microflows kunnen alleen microflows aanroepen die dit ook hebben uitstaan, andersom is die beperking er niet.

Autorisatiescenario’s

Wat de beste manier is om de autorisatie te configureren, is afhankelijk van de situatie en is niet eenduidig te beantwoorden. Een algemene regel is: Een gebruiker krijgt geen enkel recht, tenzij het niet anders kan om zijn taak uit te oefenen (hardening).

Hieronder worden enkele scenario’s beschreven. Er wordt aangegeven of het een “veilig” scenario is ten opzichte van een eventueel gebruik van de client API buiten de app om. We nemen aan dat de ontwikkelaars van de app de autorisatie binnen de app (de interactie van gebruikers met pages en services) al voldoende hebben gewaarborgd en getest (binnen de trust boundary).

Of de client API daadwerkelijk gebruikt zal worden en een bedreiging vormt, is afhankelijk van de gebruikerspopulatie en afbreukrisico. Het is altijd een afweging tussen risico’s en de ontwikkelkosten om die te beperken.

Conditionele zichtbaarheid
Indien toegangsrecht op pages en microflows ontbreekt, dan zullen menu-items en knoppen die deze pages en microflows aanroepen niet zichtbaar zijn. Het is ook mogelijk knoppen en attributen op basis van condities onzichtbaar of ingeval van attributen ook niet wijzigbaar te maken. Het alleen conditioneel onzichtbaar of niet wijzigbaar maken is niet veilig, omdat de client API deze attributen wel kan wijzigen en deze microflows wel kan aanroepen. Ook het niet kunnen openen van ongeautoriseerde pages is niet voldoende veilig om mutaties op de onderliggende data van deze pages tegen te gaan. Er is hier altijd extra autorisatie op entiteiten en attributen nodig.

Ongeautoriseerde microflows zijn wel veilig, omdat die niet via de client API kunnen worden aangeroepen.

Ook de modal status van popups of blocked uitvoeren van microflows is eenvoudig in de HTML DOM uit te schakelen (verwijderen <div> met class=”mx-underlay”).

Geprogrammeerde autorisatie
Het kan voorkomen dat autorisatieregels niet alleen gebaseerd zijn op rollen, maar ook op basis van condities in data, bijvoorbeeld een betaling mogen accorderen tot een maximum bedrag. Dit kan tot een zekere mate in Xpath-filters worden geconfigureerd en wordt dan door de client API gerespecteerd. Lukt dit omwille van de complexiteit niet meer met behulp van een Xpath-expressie, dan zal de autorisatie in een microflow moeten worden geprogrammeerd. Voordat een update (bijv. het akkoord vastleggen in een attribuut) plaatsvindt, wordt de business logica uitgevoerd die zal controleren of de update toegestaan is. Als de microflow in een before event is geïmplementeerd, dan is dit veilig, omdat het akkoord hiermee kan worden geblokkeerd. Maar wordt de microflow vanuit een page gestart (bijv. on change event of Save button), dan is dit niet voldoende om het accorderen via de client API direct in de database te voorkomen.

Uitschakelen Apply entity access
Indien Xpath-filtering voor bepaalde entiteiten niet is geconfigureerd of niet van belang is voor mutaties op de entiteiten (maar eventueel wel voor selectie), dan is het een overweging om alleen minimale leesrechten van de entiteiten en attributen uit te delen. Als dit wordt gecombineerd met updates van die entiteiten alleen uitgevoerd in microflows zonder Apply entity access, dan zorgt dit voor extra beveiliging van die entiteiten. Het is namelijk nu niet meer mogelijk om via de client API deze entiteiten te muteren. Het blijft wel mogelijk om de te selecteren objecten te beperken via het Xpath-filter. Automatische Save en Delete acties moeten dan vervangen worden door het aanroepen van zulke microflows.

Indien Xpath-filtering voor mutaties wel van belang is, bijvoorbeeld om in een multi-tennant omgeving te garanderen dat verschillende tennants niet elkaars objecten kunnen muteren (in plaats van dit bij alle microflows die mutaties uitvoeren te programmeren), dan worden de microflows altijd met Apply entity access uitgevoerd en moeten alle noodzakelijke mutatierechten worden uitgedeeld. Gevolg is dat mutaties dan ook direct via de client API plaats kunnen vinden, wel onder de restricties van het Xpath-filter.

Gebruik van non-persistent entiteiten
Een effectieve wijze van beveiligen van entiteiten is het gebruik van tijdelijke non-persistent entiteiten (NP-entiteiten). Alle communicatie en manipulatie van data met/door de gebruiker vindt dan plaats in tijdelijke NP-entiteiten. Selectie van objecten wordt uitgevoerd door een microflow die eerst alle geselecteerde data kopieert naar NP-entiteiten (zonder Apply entity access). De gebruiker ziet en muteert deze NP-entiteiten in pages. Opslag van resultaten gebeurt door aanroepen van een microflow (zonder Apply entity access) die de gewijzigde NP-entiteiten weer wegschrijft in de database.

Het grote voordeel hiervan is dat er geen enkele mogelijkheid bestaat om direct de objecten in de database te lezen en/of te schrijven. Er worden namelijk geen toegangsrechten op deze entiteiten uitgedeeld. Nadeel is dat Xpath-filtering dan niet mogelijk is. Dit scenario wijkt af van standaard Mendix en heeft wel wat ontwikkeloverhead.

Beperken aanroepen microflow
Via de client API zijn alle geautoriseerde microflows aan te roepen. Het kan ongewenst zijn dat deze zomaar buiten de context van een proces om worden aangeroepen als ze data manipuleren. Het is lastig om dit te voorkomen.

Een oplossingsrichting met forse ontwikkeloverhead is om gerelateerd aan de gebruikerssessie een object vast te leggen waarin het laatst gestarte scherm wordt bewaard. In elke aan te roepen microflow wordt dan als eerste gecontroleerd of dat op dat moment toegestaan is vanuit het laatste scherm. Dit kan worden uitgebreid met vastleggen dat de microflow reeds is aangeroepen, indien dat maar eenmaal mogelijk zou zijn. Bij het sluiten van het scherm wordt het object dan weer verwijderd.

Conclusie

Om een app volledig veilig en robuust tegen willekeurig gebruik van de client API te maken is niet standaard in Mendix beschikbaar. Dat moet serieus worden beoordeeld, ontworpen en ontwikkeld. Er is geen standaard recept voor beschikbaar.

In een volgende blog zullen we maatregelen en scenario’s beschouwen om data integer te houden.