Welkom op julesgraus.nl

Google Podcasts

23-11-2019

CSRF Tokens - Hoe werken ze nou echt?

Tegenwoordig hebben de meeste web frameworks beveiliging tegen XSRF/CSRF aanvallen. Ze zijn zo goed geïmplementeerd dat we als developers daar niet mee bezig mee hoeven te zijn. Een van die beveiligingstechnieken die websites gebruiken zijn XSRF token. Laten we een kijkje nemen naar hoe ze echt werken!

Wat is XSRF/CSRF

Het is een afkorting voor Cross Site Request Forgery. Hiermee wordt vanuit het perspectief van een slachtoffer, onbedoeld een actie in een website uitgevoerd waarop hij is ingelogd. Deze actie word bedoelt geforceerd door een aanvaller.

Waarom is dat een probleem?

Stel dat een slachtoffer persoonlijke informatie heeft staan in een website, en via een XSRF aanval word zijn e-mailadres gewijzigd. Dan kan een aanvaller bijvoorbeeld het wachtwoord resetten van de account via het nieuwe e-mail address en volledige toegang krijgen tot die gevoelige gegevens. Zonder dat het slachtoffer dit zelf kon voorkomen.

Een concreet voorbeeld: Een aanvaller heeft via de aanvaller de account overgenomen van Johny Modaal, de zoon van Jan Modaal. De account is van een social media website, example.org, waarmee Johny Modaal vaker berichtjes stuurde naar zijn vader.

In 1 van de berichten vind de aanvaller een bericht waarin Johny aangeeft dat hij pech heeft met zijn vlucht naar huis, maar dat hij wellicht naar huis kan komen als hij van zijn kameraad wat centjes kan lenen.

De aanvaller zou hier bijvoorbeeld een Berichtje naar vader Jan kunnen sturen met daarin het verzoek of hij wat geld kan overmaken naar zijn "Nieuwe rekening" aangezien die vriend toch niet over genoeg geld beschikt. De vader zal wellicht niet veel vermoeden aangezien de aanvaller inhaakt op een gesprek wat al bezig was. Met als gevolg dat de Vader wordt opgelicht.

Hoe werkt dat dan?

Een concreet voorbeeld:

Het is het best uit te leggen aan de hand van een heel concreet voorbeeld. Datzelfde als wat ik hierboven aanhaalde.

Door eerder onderzoek is de aanvaller erachter gekomen dat wanneer hij zijn e-mail adres veranderde op de social media website example.org dat ging via een GET request naar deze url:

http://www.example.org?change_email_to=attackersnew@example.org

Hij had daarna zij e-mailadres weer weer veranderd naar zijn oude.

Hij vond Johny op social media een aantrekkelijk slachtoffer omdat Johny openbaar berichtte dat hij op vakantie via met fictief bedrijf flyacme.org was en over enkele dagen terug kwam. Dit geeft de aanvaller een draagvlak om de aanval op uit te gaan voeren.

De aanvaller maakt een e-mail account aan met de naam flyacme-helpdesk@gmail.com. Via dat e-mail bericht doet hij zich voor als iemand van de klantenservice van flyacme.org. En bedankt hem voor het leuke berichtje op social media. Dat doet hij door Johny een betere stoel aan te bieden in het vliegtuig waarmee hij zal terug komen. Namelijk in de business class. Maar Johny moet het aanbod accepteren door op een bepaalde link te klikken in dat mailtje.

Nietsvermoedend klikt Johny op die link en komt op een website uit die lijkt op die van flyacme.org. Een website die door de aanvaller in elkaar is gezet. Er komt een melding in beeld dat het aanbod verlopen is. Op de pagina staat ook een plaatje van 0 x 0 pixels die de XSRF aanval uitvoert:

<img src="http://www.example.org?change_email_to=attackersnew@example.org" width="0" height="0">

Op het moment dat de pagina in beeld komt, zal de browser het plaatje willen laden. Maar je ziet het plaatje niet omdat hij 0 x 0 pixels groot is. Maar in de plaats van dat het plaatje geladen word voert de browser een GET request uit op de url die in de src staat. Johny is op dat moment ook ingelogd op die social media website. Hierdoor word bij de GET request ook automatisch door de browser zijn session cookie meegestuurd. De social media website ontvangt de request en de session cookie. Hiermee ziet hij dat de cookie van Johny is, en dat hij zijn e-mail adres wil veranderen. En veranderd het e-mail adres naar het e-mail adres van de aanvaller.

Vanaf dat punt heeft de aanvaller vrij spel en kan hij het wachtwoord van de account resetten via de social media website door zijn e-mail adres te gebruiken. En dan kan hij zich voordoen als Johny en geld ontfutselen van de vader.

Technisch samengevat

Dit is wat er technisch gezien gebeurde

Wat is een CSRF token?

Een CSRF token is een niet te raden willekeurige code die meestal uit een random number generator komt met een vast geheim daaraan vast. Het zou bijvoorbeeld een willekeurig getal kunnen zijn van minimaal 10 tekens lang met daarachter een vast nummer van 5 cijfers.

Hoe word de token gebruikt?

Als iemand een web pagina bezoekt wordt deze token in de session van de gebruiker gezet. De gebruiker krijgt dan de pagina te zien en in alle formulieren op die website, word dan bijvoorbeeld in een hidden input de CSRF token gezet. Zodat deze als de gebruiker een formulier instuurt, de CSRF token ook meestuurt. De server vergelijkt dan de token die in sessie van de gebruiker staat, met die van het formulier. Als deze overeenkomen, zal de server de actie uitvoeren, bijvoorbeeld dat e-mail adres veranderen. Zo niet, dan zal de server dat niet doen. Probleem opgelost!

Maar een aanvaller kan toch ook gewoon de code gebruiken?

Ja dat klopt. De aanvaller kan in zijn formulier ook een token plaatsen die hij van te voren van de website af schraapt. Maar toch kan hij daar niets mee. Waarom niet? De token die de aanvaller krijgt, zit in de sessie van de aanvaller. En niet in de sessie van het slachtoffer. Het plaatje van de aanvaller ziet er technisch gezien dan zo uit:

<img src="http://www.example.org?change_email_to=attackersnew@example.org&csrf_token=984637463872341" width="0" height="0">

De server krijgt dan die request binnen met de session cookie van het slachtoffer. Hierdoor word de session opgehaald van het slachtoffer en die heeft een andere token als die van de aanvaller.

De kracht zit hem hier dat het voor de aanvaller vrijwel niet te voorspellen is wat de waarde is van de CSRF token van een slachtoffer.

Ik zeg vrijwel niet want als de website bijvoorbeeld nog eens kwetsbaar zou zijn voor session hijacking, het mogelijk zou moeten zijn om dat wel te weten. Maar dat is een ander probleem, met een andere oplossing.

Waar moet ik op letten bij het implementeren van de tokens?

Onderzoek voor jezelf hoe je de gebruiker op andere manieren per ongeluk die request kan laten doen. Het voorbeeld van de plaatjes hier veroorzaakt een GET request. En als je alleen bij GET request de tokens checked, heb je het probleem nog niet helemaal opgelost. Want het is ook mogelijk om in een website een javascriptje te plaatsen die een POST, PUT, DELETE enzovoorts request doet. In dat geval kan de aanval wel uitgevoerd worden met een andere methode, zoals POST.

Zorg er tevens voor dat wanneer je geen token ontvangt van een formulier, dat je dan niet de CSRF controle overslaat. Want dan kan als nog de aanval worden uitgevoerd.

Link tevens de code aan een gebruiker. Bijvoorbeeld door de code in een sessie op te slaan. Er zijn wel eens foutieve implementaties geweest die dat niet deden. Daar werd bijvoorbeeld vooraf een reeks tokens gemaakt en opgeslagen. Deze waren dan niet gelinkt aan specifieke gebruikers. Maar als iemand dan een formulier instuurde, werd gekeken of de ingestuurde token in die reeks voorkwam. En dan werd de verkeerde aanname gedaan dat dat veilig was. Juist doordat een token aan 1 specifieke gebruiker gelinkt is, kan een aanvaller niet met een andere token iets namens die gebruiker doen.

Bedenk ook dat de kwaadaardige requests niet persee uit de browser hoeven te komen. Ze kunnen bijvoorbeeld ook ontstaan doordat iemand een HTML e-mail opent, met daarin een plaatje met verdachte link. Tegenwoordig zijn zulke aanvallen moeilijk geworden doordat e-mail providers en clients, proxies gebruiken die eerst het plaatje via een andere computer voor je ophalen, zodat de request vanaf jou computer niet mogelijk is.

Kijk ook naar gerelateerde beveiligingsuitdagingen als XSS, de verkeerde gespelde Referer header, Cross domain policies enzovoorts.

Let op, ik probeer hier niet te beweren als je deze uitdagingen allemaal oplost, dat je dan veilig zit. Neem mijn advies als een goede richting aan. En experimenteer er zelf mee zodat je weet waar je mee bezig bent. Ik ben niet aansprakelijk voor eventuele schade in welke vorm dan.