PHP-Sikkerhet del 2

CSRF er en alvorlig type angrep som gjør at angriperen kan få andre brukere til å utføre en hvilken som helst handling på en hvilken som helst nettside hvor det ikke er beskyttelse mot CSRF. Lær hvordan du kan sikre dine websider.

En ting er at noen slenger rundt med linker som peker til onde scripts via et annet nettsted (les mer om dette i del 1 av denne guiden). Men det finnes andre metoder som gjør det mulig å få andre brukere til å utføre handlinger på nettsteder uten at de trykker på noen som helst link i det hele tatt. Cross-Site Request Forgery (CSRF) er ikke et kjent begrep, noe som gjør det enda farligere…

Hvordan et sikkerhetshull oppstår

Jeg drar frem et eksempel for å vise hvordan det fungerer, da det blir enklere å forstå konseptet. La oss tenke oss at vi har laget et forum, et forum som har veldig mange brukere. Alle brukere har tilgang til en egen konto der de kan ha egne prosjekter som de kan dele med andre (noe ala scorceforge). I forumet er det også mulig å legge ved bilder (slik som på ITpro). En bråkmaker er ute etter bråk (naturligvis), og posterer i forumet med et bilde. Kort tid etterpå får vi beskjed fra veldig mange sinte brukere om at prosjektene deres har blitt slettet.

Vi finner ut at bråkmakerens bilde peker til:
http://eksempel.forum.no/prosjekt.php?op=delete

Som du ser peker bildet til slette-funksjonen til prosjektet vårt. Den samme adressen som den røde “Slett prosjektet ditt”-knappen alle brukere har i prosjekt-delen av brukerkontoen. Når nettleseren til alle brukerne skal hente bildet, så må den sende en etterspørsel etter bildet til serveren, akkuratt som med websider. Serveren får etterspørselen og behandler den som den er, en addresse til et script, og kjører scriptet. Nettleseren får ikke noe bilde tilbake, og brukerne ser bare et ugyldig bilde (i form av et kryss i IE). Men serveren behandler scriptet, sjekker om bruker er innlogget, finner frem bruker-ID og sletter prosjektet til brukeren som utfører den valgte handlingen (op=delete). Resultatet er katastrofalt for de som prøver å “se” bildet til bråkmakeren.

Tett sikkerhetshullet

Problemet her er at angriperen kan få en annen bruker til å utføre en handling, som om det var brukeren selv som ønsket det. Det går altså ikke an å se forskjell, og det er ingenting vi kan gjøre for å hindre slike angrep heller, så lenge det er mulig å bruke bilder på Internett.

Løsningen blir å legge til en unik nøkkel i adressen, som “beviser” at handlingen blir utført av riktig bruker. Se for deg denne koden:

 if (!isset($_SESSION['token'])) {   $_SESSION['token'] = md5(uniqid(rand(), true)); } $link_token = "?t=" . $_SESSION['token']; $eksempel_link = "http://eksempel.forum.no/prosjekt.php" . $link_token . "&op=delete"; echo "<a href=$eksempel_link>Slett!</a>"; 


Her lager vi en helt tilfeldig og unik nøkkel og lagrer den i klientens sessions (som ligger på serveren). Nøkkelen blir plassert i alle linker som peker til script som utfører handlinger (f.eks. å slette noe). prosjekt.php sjekker om linkens nøkkel stemmer med klientens nøkkel som er lagret på serveren:

 if (isset($_SESSION['token']) AND isset($_REQUEST['t'])) {   if ($_SESSION['token'] == $_REQUEST['t']) {     /* Riktig nøkkel, utfør handling */   } } 


Dermed har vi som godt som eliminert mulighetene for et CSRF-angrep i prosjekt.php. Eneste måten en angriper kan få en annen bruker til å utføre en handling, er å gjette seg frem til nøkkelen til den andre brukeren, noe som er nærmest umulig.

Sikre skjemaer

Det er ikke bare linker du må sikre for CSRF-angrep. En angriper kan lett finne ut hvordan dine skjemaer er oppbygd ved å se på kildekoden. Ved å legge til et skjult felt med den unike nøkkelen, kan vi oppnå den samme beskyttelsen som med linker:

 <input type="hidden" name="t" value="{$_SESSION['token']}" /> 

Kommentarer