Een cyber security specialist van WhiteHats die een workshop geeft

Extreme sessiebeveiliging

Introductie

Niet al te lang geleden hebben we geblogd over onze (mis)avonturen in het vinden van nieuwe kwetsbaarheden in populaire software. We hebben kort genoemd hoe cookies en WebStorage hun eigen reeks beveiligingsvoordelen en uitdagingen met zich meebrengen. Door ze te combineren, stellen we ons een sessiebeheeroplossing voor met absurde beveiligingseigenschappen.

CSRF en XSS

Laten we kort praten over twee veelvoorkomende kwetsbaarheden van webapplicaties:

  • Cross-Site Request Forgery (CSRF)
  • Cross-Site Scripting (XSS)

CSRF-aanvallen werken door slachtoffers te misleiden om kwaadaardige verzoeken naar de applicatie te sturen. Deze verzoeken worden vanuit de browser van het slachtoffer met de cookies van het slachtoffer verzonden. De aanvaller kan de serverreactie niet ontvangen. De aanval activeert echter wel gedragsveranderingen op de server (aangezien de gebruiker is ingelogd), zoals het maken van een nieuwe gebruiker, het toewijzen van een rol of het wijzigen van een wachtwoord, waar de aanvaller op uit is.

XSS-aanvallen maken gebruik van de eigenschap van de browsers om JavaScript van vertrouwde domeinen uit te voeren in de context van het ingelogde slachtoffer. Deze scripts kunnen gevoelige informatie targeten die door de browser wordt bewaard en paginainhoud vervalsen.

Het web staat vol met methoden om deze aanvallen te voorkomen:

  • Security headers
  • Anti-CSRF tokens
  • Sanitizing input
  • Escaping output
  • Et cetera ...

De voorgestelde oplossing is geen vervanging van bestaande oplossingen, maar eerder een aanvullend verdedigingsmechanisme. Deze 'defence-in-depth'-maatregel maakt gebruik van de eigenschappen van cookies en WebStorage om het volgende te bereiken:

  • CSRF voorkomen.
  • Het stelen van sessietokens/JWT's zinloos maken.

Cookies vs. WebStorage

De kracht en zwakte van Cookies en WebStorage verschillen en kunnen worden benut om een oplossing te creëren die het beste van twee werelden biedt.

Allereerst: cookies. Ze zijn oud, alomtegenwoordig en vrij veilig zolang je de beveiligingsfuncties gebruikt. Cookies kunnen grotendeels worden beschermd tegen XSS-aanvallen door 'HttpOnly' in te schakelen, waarmee je cookies beschermt tegen directe JavaScript-interactie. Cookies worden samen met de HTTP-headers met elk browserverzoek naar de server verzonden. Als je de relatief nieuwe 'SameSite'-richtlijn niet gebruikt (en de meeste applicaties doen dat nog niet), voegt je browser cookies toe aan elk verzoek naar de server, ongeacht de oorsprong van het verzoek. Aanvallers kunnen deze functie misbruiken voor CSRF-aanvallen.

Opmerking: door de 'SameSite'-richtlijn in te stellen op 'strict', worden je cookies beschermd tegen verzoeken van andere vanaf domeinen. Je cookies kunnen nu niet meer worden misbruikt voor CSRF. De enige browser die de 'SameSite'-richtlijn niet ondersteunt, is Internet Explorer, en die moet hoe dan ook worden vermeden.

WebStorage is ontworpen als een betere plek om gebruikersgegevens op te slaan dan cookies. WebStorage kan alleen worden benaderd via JavaScript en de toegang is beperkt tot het domein van de applicatie (bijv. app.whitehats.nl). Ontwerpmatig kan WebStorage niet worden misbruikt voor CSRF. Echter, op dezelfde manier, is gegevens opgeslagen in WebStorage altijd kwetsbaar voor XSS. Over het algemeen is het een goed idee om gevoelige gegevens te versleutelen als je ze gaat opslaan in WebStorage.

Stel dat er een hypothetische webapplicatie is die werkt met een sessietoken (of een JWT voor stateless authenticatie) na gebruikersauthenticatie. Waar ga je deze gevoelige gegevens opslaan? Kies je ervoor om kwetsbaarder te zijn voor CSRF (cookies), of kies je ervoor om het impact van een succesvolle XSS-aanval te vergroten (WebStorage)?

Als WebStorage niet gevoelig is voor CSRF en cookies niet voor XSS, waarom zouden we dan niet beide gebruiken?

Het beste van twee werelden

Genereer een willekeurige string (veilig) na authenticatie en voeg deze toe aan het authenticatietoken dat naar de client wordt verzonden. Neem een hash (HMAC-SHA2) van de willekeurige string en een (geheime) sleutel en stuur deze hash ook naar de client. Sla het token op in een cookie en de hash in LocalStorage (of andersom).

Stuur zowel de hash als het token bij elk verzoek naar de server, en controleer de associatie tussen de twee. De server moet elk verzoek dat authenticatie vereist en waarbij de associatie tussen de twee waarden ontbreekt, afwijzen.

Deze benadering kan worden beschouwd als een 'defence-in-depth'-techniek. Wel is het de vraag of de winst in beveiliging opweegt tegen de moeite die nodig is om deze benadering te implementeren en onderhouden. Dit geldt des te meer als je weet dat moderne cookie-attributen zoals SameSite een vergelijkbaar beschermingsniveau kunnen bieden. En bovendien moeten applicaties in de eerste plaats beschermd worden tegen CSRF- en XSS-aanvallen.