Moderne beveiliging voor single page applications

Geschreven door Merlin Bieze en Maarten Louage op

Als developer heb je het vast wel meegemaakt, een klant vraagt om een web applicatie; moet van alles kunnen doen, moet gebruiksvriedelijk zijn, snel, dit gaat hét nieuwe platform worden! En, oh ja, gebruikers moeten veilig kunnen inloggen, SSO support voor social media accounts? Yes please!

Het duizelt je als je bedenkt wat daar allemaal voor nodig is. Gelukkig kun je terug vallen op industrie standaarden en best practices. OAuth (2.0), een beveiligingsprotocol ontwikkeld binnen de IETF, beschrijft de workflow voor verschillende typen applicaties. Zo ook voor een SPA (single page application). Uiteraard moet je nog wel het een en ander inregelen, maar voor de meeste programeer- scriptingtalen zijn er duidelijke beschrijvingen te vinden die je daarbij helpen. Met relatief weinig moeite kun je al snel een state-of-the-art beveiligde gebruikers login voor de website opzetten. Vertrouwend op het feit dat een groot deel van het Internet precies dezelfde methode gebruikt, dan moet het wel goed zijn toch?

Voordat we daar antwoord op kunnen geven is het handig om in het kort de gedachte achter OAuth uit een te zetten en een aantal termen te introduceren.

Het OAuth protocol is door verschillende IDPs (identity providers) geïmplementeerd, allen werken ze volgens het zelfde principe; de IDP stelt zich op als een vertrouwde partij waarbij een gebruiker zich middels de gebruikelijke authenticatie methoden aanmeldt (gebruikersnaam, wachtwoord, mfa, etc). Na een correcte login geeft de IDP een token (identiteitsbewijs) terug, een stukje tekst waarin kenmerken van de gebruiker worden beschreven en tot welke applicatie server(s) er toegang is. Om de loginsessie in stand te houden, moet het token in de applicatie beschikbaar blijven, bijvoorbeeld door het op te slaan. Als de gebruiker vervolgens vanuit de applicatie een bericht naar de applicatie server stuurt wordt het token bijgesloten.

Doordat de IDP het token digitaal heeft ondertekend kan de applicatie server verifiëren dat elk bericht een door de IDP uitgegeven token bevat waarvan de inhoud niet (stiekem) is gewijzigd. De applicatie server kan er nu op vertrouwen dat het ontvangen bericht daadwerkelijk van de ingelogde gebruiker afkomstig is.

Zoals gezegd moet het token bewaard worden in de SPA zodat de gebruiker geïdentificeerd kan worden door de applicatie server. Als we het over een web applicatie hebben dan is de browser een logische plek om dat te doen. Helaas is de opslag van de brower niet beveiligd. Je kunt de tokens van een ingelogde sessie gewoon bekijken.

En met een website als https://jwt.io/ kun je de inhoud van een gecodeerde token ook uitlezen. Dit betekent dat er geen geheime informatie in een token mag zitten, het is immers erg makkelijk in te zien! Dit is onder andere de reden waarom een token ook maar kort geldig mag zijn: stel het token valt in verkeerde handen dan kan de login niet ‘lang’ gekaapt worden. Dat voelt allemaal niet heel veilig..

Het is daarnaast ook goed om je te realiseren dat een browser SPA onderhevig kan zijn aan meerdere aanvallen waarbij de token ontvreemd kan worden, denk bijvoorbeeld aan malafide code in een third-party script die een XSS aanval mogelijk maakt, of een geïnstalleerde browser-extension van de gebruiker die toegang heeft tot de browser storage. In dit laatste geval kun je er als SPA developer helemaal niets aan doen om dat tegen te gaan!

Nu zijn er uiteraard manieren om een token wel veilig(er) op te slaan in de browser, bijvoorbeeld door de token in een HTTP-Only cookie te stoppen, hier mag code die in de browser draait niet bij. Maar toch vertrouwen we het token nog steeds toe aan een onveilige browser omgeving.

Uiteraard was dit een bekend probleem, eigenlijk als sinds de introductie van OAuth 2.0. Toch was het vanwege allerlei technische beperkingen in het verleden niet makkelijk om van de browser opslag af te stappen bij het implementeren van een SPA. Een acceptabel risico zeg maar. Gelukkig zijn er de afgelopen tijd nieuwe en ook weer oudere patronen opgedoken waarbij het token niet meer naar de browser hoeft te worden gestuurd, een voorbeeld daarvan zullen we verder in deze blog introduceren: BFF (Backend For Frontend).

Dit is meteen al het ironische in dit verhaal, om heel dit zaakje veiliger te maken vallen we terug op oudere methoden. Een belangrijke factor bij de BFF zijn cookies. Cookies hebben een niet al te beste reputatie, ze houden bij waar je overal op het internet bent langsgeweest, ze bevatten data die voor marketing bedrijven wel interessant kan zijn enzovoorts. Toch zijn de grote browser makers wel verder gegaan om cookies meer privé te maken. Je hebt verschillende instellingen die ervoor zorgen dat cookies niet meer je domein zoals *.xprtz.net of zelfs je subdomein mogen verlaten, zoals www.xprtz.net. Combineer dat met het feit dat cookies extra opties hebben zoals de eerdere vermeldde HTTP-Only vlag en je krijgt een robuster en veiliger systeem.

Houden we nu een pleidooi om weer terug te gaan naar het oude cookie systeem voor logins? Helemaal niet. Cookies worden met het BFF patroon gecombineerd met een backend systeem. Het is dat backend systeem dat de afhandeling van de tokens voor zich gaat nemen. Wat eerder dus in een onveilige browser gebeurde, zal nu gebeuren in een veilige server omgeving.

BFF

Het BFF-patroon is dus geniaal in zijn eenvoud: de browser is niet meer veilig te noemen om tokens af te handelen dus daar zullen we dat niet meer doen en we verplaatsen die functionaliteit naar een backend applicatie. Die backend kan dan weer gebruik maken van de bekende authenticatieflows zoals de Authorization Code flow, met als voordeel dat het om een zogenaamde confidential client gaat waardoor we kunnen terugvallen op authenticatie met secrets of certificaten. Cookies zijn dus belangrijk voor de communicatie tussen de webapplicatie en de BFF en niet meer dan dat. Denk bijvoorbeeld aan het weergeven van je naam als je ingelogd bent in een webapplicatie.

Het maken van zo’n BFF is zeker voor .NET projecten vrij eenvoudig geworden. Duende Software, bekend van IdentityServer, heeft een Nuget package uitgebracht die de opzet van een BFF-project al voor ons doet. Uit onderstaande afbeelding kan je opmaken dat een BFF verder bouwt op bestaande technologieën.

BFF

Moeten we nu als de bliksem alle projecten waarbij er een login systeem aanwezig is gaan vervangen? Nee, het is niet zo dat je huidige webapplicatie met een Authorization Code flow with PKCE opeens onveilig is geworden. Inzichten in de securitywereld veranderen gewoon en dat is maar goed ook. Ons advies is, kijk goed naar de data die je hebt. Oma’s website om recepten te beheren zal niet zo nodig baat hebben bij het gebruik van een BFF maar werk je aan een applicatie met medische of financiële gegevens dan zou het niet gek zijn om te kijken hoe een BFF binnen je applicatie architectuur kan passen.

Heb je na het lezen van dit artikel nog prangende vragen? Laat gerust iets weten en we komen graag met jou in contact.

Bronnen:

Maarten LouageMaarten is een .NET expert met een focus op software architectuur die past bij de cloud, zowel op de backend als op de frontend. Maarten werkt momenteel als hands-on software architect bij Action en helpt bij het ontwerpen en opzetten van een nieuw digitaal platform.
Merlin BiezeMerlin is een .NET expert met affiniteit voor big data processing in Azure cloud en cyber security. Momenteel werkt hij als senior software engineer bij Royal HaskoningDHV.
← Terug
XPRTZ