Cross-Site Request Forgery (CSRF): Når Din Browser Handler Imod Dig
Cross-Site Request Forgery – oftest forkortet CSRF (udtales “sea-surf”) – er en snigende webangrebstype, der udnytter den tillid, en hjemmeside har til din browser. Mens XSS udnytter den tillid, en brugers browser har til en hjemmeside, vender CSRF det på hovedet: her er det hjemmesidens server, der narres til at tro, at en ondsindet anmodning kom fra den autentificerede bruger.
Angrebet er listet på OWASPs Top 10 og har historisk ligget bag spektakulære angreb – fra uautoriserede bankoverførsler til kontoovertag. I denne artikel gennemgår vi mekanikken bag CSRF fra grunden, ser på reelle eksempler, og undersøger de moderne forsvarsmekanismer.
1. Forudsætningerne: Cookies og SOP
For at forstå CSRF skal vi forstå to fundamentale web-mekanismer.
Session Cookies
Når du logger ind på en hjemmeside (f.eks. din netbank), udsteder serveren en session cookie til din browser. Denne cookie er beviset på, at du er autentificeret. Din browser gemmer cookien og sender den automatisk med alle fremtidige HTTP-anmodninger til det pågældende domæne – uanset hvorfra anmodningen stammer.
Det er dette “automatisk”-aspekt, som er kernen i CSRF-problemet.
Same-Origin Policy (SOP)
Browsers håndhæver Same-Origin Policy (SOP), som forhindrer en ondsindet hjemmeside i at læse svar fra et andet domæne. Men SOP forhindrer ikke browseren i at sende anmodninger til et andet domæne. En form på evil.com kan sagtens POST til bank.dk – browseren sender blot session-cookien med automatisk, og serveren ved ikke, at anmodningen kom fra et fremmed site.
2. Angrebet Trin for Trin
Lad os gå igennem et konkret angrebsscenarie:
Opsætning: Din netbank, bank.dk, har et endpoint til pengeoverførsler:
POST /overfør HTTP/1.1
Host: bank.dk
Cookie: session=abc123xyz
modtager=12345678&beloeb=50000
Serveren er ligeglad med hvor anmodningen kom fra, så længe session-cookien er gyldig.
Angrebet:
- Du er logget ind på
bank.dkog har en aktiv session-cookie i din browser. - Du besøger en ondsindet hjemmeside,
evil.com, mens du stadig er logget ind. evil.comindlæser denne skjulte HTML i sin side:
<!-- Skjult iframe eller auto-submit form på evil.com -->
<form id="csrfForm" action="https://bank.dk/overfør" method="POST">
<input type="hidden" name="modtager" value="98765432">
<input type="hidden" name="beloeb" value="50000">
</form>
<script>
document.getElementById('csrfForm').submit();
</script>
- Din browser eksekverer automatisk JavaScript’et, som straks sender
POST-anmodningen tilbank.dk. - Din browser vedhæfter automatisk din gyldige session-cookie til anmodningen.
bank.dks server modtager en tilsyneladende legitim, autentificeret anmodning og overfører 50.000 kr. til angriberens konto.
Du opdagede ingenting. Din browser handlede imod dig, og serveren stolede blindt på din browser.
3. Angrebsvarianter
CSRF kan udføres på mange måder, afhængigt af hvilken HTTP-metode målendpointet benytter.
GET-baseret CSRF
Hvis en kritisk handling udføres via en simpel GET-anmodning (hvad der betragtes som dårlig webpraksis), er angrebet endnu nemmere:
<!-- Et enkelt billede er nok -->
<img src="https://bank.dk/overfør?modtager=98765432&beloeb=50000" width="0" height="0">
Browseren forsøger at indlæse billedet og sender automatisk GET-anmodningen (med cookie). Ingen JavaScript nødvendig.
POST-baseret CSRF
Som vist i eksemplet ovenfor. Kræver en HTML-form med method="POST" og typisk JavaScript til automatisk indsendelse.
JSON-baseret CSRF
Moderne API’er bruger typisk Content-Type: application/json, men her er det mere kompliceret. En standard HTML-form kan kun sende application/x-www-form-urlencoded eller multipart/form-data. Browseren kræver en CORS preflight-anmodning for custom content-types, som normalt blokerer angrebet. Dog er ikke alle servere konfigureret korrekt, og nogle APIs accepterer data uanset Content-Type.
4. Historiske Eksempler
Netflix (2006): En CSRF-sårbarhed i Netflix tillod en angriber at tilføje film til en brugers udlejningskø, ændre kontoindstillinger og potentielt ændre leveringsadressen – alt uden brugerens vidende.
Gmail (2007): En sårbarhed i Gmail tillod angribere at opsætte automatiske videresendelsesregler for en brugers e-mails. Et enkelt besøg på en ondsindet side mens man var logget ind på Gmail, og alle fremtidige e-mails kunne automatisk kopieres til angriberen.
ING Direct (2008): En CSRF-sårbarhed i den amerikanske bank ING Direct tilladte uautoriserede bankoverførsler. Angrebet krævede blot, at ofret besøgte en ondsindet side mens de var logget ind på bankens hjemmeside.
5. Forsvar mod CSRF
Moderne webapplikationer bør implementere et eller flere af følgende forsvarsniveauer.
1. CSRF Tokens (Synkroniserings-Token Mønster)
Dette er den mest udbredte og robuste forsvarsmetode. Princippet er:
- Serveren genererer et tilfældigt, unikt og hemmeligt CSRF-token for hvert bruger-session.
- Dette token indlejres i alle HTML-forms som et skjult felt:
<form action="/overfør" method="POST">
<input type="hidden" name="csrf_token" value="a3f9b7c2e1d8...">
<input type="text" name="beloeb">
<button type="submit">Overfør</button>
</form>
- Når formularen indsendes, validerer serveren at det modtagne token matcher det token, der er gemt i brugerens session.
- En angriber på
evil.comkender ikke dette tilfældige token (SOP forhindrer dem i at læse indholdet af bank.dk-sider), og kan derfor ikke konstruere en gyldig ondsindet anmodning.
Vigtig regel: CSRF-tokenet må aldrig sendes i en cookie – det defeats hele formålet.
2. SameSite Cookie-attributten
SameSite er en moderne cookieattribut, der direkte adresserer CSRF ved at kontrollere, hvornår browseren må sende cookies med cross-site anmodninger:
Set-Cookie: session=abc123xyz; SameSite=Strict; Secure; HttpOnly
Der er tre niveauer:
| Værdi | Beskrivelse | CSRF-beskyttelse |
|---|---|---|
Strict | Cookie sendes kun ved anmodninger fra samme site. | Stærk |
Lax | Cookie sendes kun med top-level navigation (klik på links), ikke skjulte forms/iframes. | Moderat |
None | Cookie sendes altid med cross-site anmodninger. Kræver Secure. | Ingen |
SameSite=Strict giver den stærkeste beskyttelse, men kan bryde legitime use cases (f.eks. links fra en e-mail). SameSite=Lax er en god standard der beskytter mod de fleste CSRF-angreb, og er faktisk standard i moderne browsere (Chrome, Firefox) for cookies uden en eksplicit SameSite-attribut.
3. Validering af Origin- og Referer-headere
Serveren kan inspicere HTTP-headerne Origin og Referer, som angiver hvorfra anmodningen stammer, og afvise anmodninger fra ukendte domæner.
# Pseudokode
def validér_csrf(request):
origin = request.headers.get('Origin')
if origin and origin != 'https://bank.dk':
afvis_anmodning()
Denne metode er dog ikke 100% pålidelig: Referer-headeren kan undertrykkes af privacy-indstillinger eller proxies, og Origin sendes ikke altid. Det bør bruges som et supplerende lag, ikke som primært forsvar.
4. Double Submit Cookie-mønster
Et alternativ der ikke kræver server-side session-lagring. Serveren sætter et tilfældigt CSRF-token i en cookie og kræver at samme token sendes som en separat parameter (f.eks. i en skjult form-felt eller HTTP-header). Da evil.com ikke kan læse ofrets cookies (SOP), kan de ikke kopiere token-værdien over i en form.
5. Kræv Brugerinteraktion for Kritiske Handlinger
For særligt kritiske operationer (bankoverførsler, sletning af konto, ændring af adgangskode) bør applikationen kræve re-autentificering (f.eks. at brugeren gentaster sin adgangskode eller bekræfter via MFA). Dette kan ikke forfalske via CSRF, da angriberen ikke kender adgangskoden.
6. CSRF vs. XSS
Disse to angreb forveksles ofte, men er fundamentalt forskellige:
| CSRF | XSS | |
|---|---|---|
| Angrebsmål | Serverens tillid til browseren | Brugerens tillid til hjemmesiden |
| Kræver JavaScript? | Nej (GET-baseret) / Normalt (POST) | Ja |
| Hvad kompromitteres? | En enkelt, specifik handling | Hele sessionen, data, DOM |
| Angriberen ser svaret? | Nej | Ja |
| Primært forsvar | CSRF-tokens, SameSite cookies | Output encoding, CSP |
En vigtig pointe: En XSS-sårbarhed kan invalidere CSRF-beskyttelse! Hvis en angriber kan køre JavaScript på bank.dk via XSS, kan de blot læse CSRF-token direkte fra DOM’en og inkludere det i deres CSRF-anmodning.
7. Konklusion
CSRF er et elegantisk og snigende angreb, der udnytter en browser-funktion der ellers er essentiel for webbets funktion: automatisk afsendelse af session-cookies. Angrebet kræver ingen kompleks teknisk formåen fra angriberens side – blot at offeret besøger en ondsindet side mens de er autentificerede et andet sted.
Det gode nyhed er, at beskyttelsen er veletableret og relativt simpelt at implementere. CSRF-tokens og SameSite=Lax cookies er i dag standard i de fleste moderne web-frameworks (Django, Rails, Spring, ASP.NET Core) og aktiveret som standard. For udviklere er de vigtigste takeaways:
- Brug et webframework der håndterer CSRF-tokens automatisk.
- Sæt altid
SameSite=StrictellerSameSite=Laxpå session-cookies. - Brug aldrig GET-anmodninger til at udføre tilstandsændringer (sletning, opdatering, overførsler).
- Kræv re-autentificering for særligt kritiske handlinger.
- Husk at XSS kan nedbryde dine CSRF-forsvar – sikre begge fronter.
Kilder
- OWASP: Cross-Site Request Forgery (CSRF) – OWASPs autoritære gennemgang af CSRF-angrebet med tekniske detaljer og forsvar.
- OWASP: CSRF Prevention Cheat Sheet – OWASPs praktiske guide til udviklere om implementering af CSRF-beskyttelse.
- MDN Web Docs: SameSite cookies – Teknisk dokumentation af
SameSite-attributten og dens effekt. - PortSwigger Web Security: Cross-site request forgery (CSRF) – Dybdegående teknisk forklaring og interaktive labs fra eksperterne bag Burp Suite.
- Google Security Blog: Tough Cookies – Googles forklaring af ændringen af standard
SameSite-adfærd i Chrome 80.
> Quiz: Test din viden
1. Hvad udnytter CSRF primært i browserens adfærd?
2. Hvad er den mest udbredte forsvarsmekanisme mod CSRF i formularer?
3. Hvilken cookie-attribut reducerer cross-site cookie-afsendelse?
4. Hvilken policy forhindrer typisk læsning af svar på tværs af domæner?