Barn har ingen grenser for hva slags galskap de kan finne på, til foreldrenes store forferdelse. Det samme gjelder for nettlesere, de kan finne på mye rart som brukerne ikke liker eller vet om. Dette er et forsøk på å forklare Content Security Policy (CSP) som en slags barnevakt for nettlesere.
¶Hva er Content Security Policy?
Content Security Policy er et viktig verktøy i verktøykassen når man sikrer en nettside. Det bidrar til å oppdage og begrense visse typer angrep, i hovedsak Cross-Site Scripting (XSS). Det innebærer at hackere klarer å lure inn ondsinnet innhold på nettsiden med formål å endre utseende eller oppførsel. En angriper har mange måter å utføre XSS-angrep på.
Dette viser hvor viktig det er å vaske alt innhold som kommer fra utsiden.
Så hvordan hjelper Content Security Policy mot XSS? Å skrive om HTTP-headere kan fort bli tørt og kjedelig, så her skal jeg forsøke meg på en vri.
¶Hold deg fast, for her kommer en allegori
Se for deg en nettside som en lekeplass full av morsomme lekestativ. Et sted hvor brukere sender nettleserne sine for å leke. Hvert lekestativ har skilt med regler som forklarer hvordan de skal brukes.
nettleserne er ekstremt oppdragne og følger alltid reglene. Lekeplassen er også pyntet med fine bilder.
Brukerne stoler blindt på at lekeplassen er trygg. Når nettleseren er ferdig på lekeplassen, forteller de til brukerne hva de har gjort og sett.
La oss ta en nærmere kikk på hva som skjer når Bente Bruker sender Nils Nettleser inn på supersnill.no-lekeplassen.
På skiltet til lekeplassen henger det et hengelås-ikon, og det tolker Bente Bruker på at dette er en lekeplass hun kan stole på.
I det mørkeste hjørnet av lekeplassen henger det noen ordentlig slemme bøller. Det eneste de vil er å plage, rane og ødelegge for de som leker. Favorittaktiviteten deres er cross-site-scripting-rampestreker.
Etter en stund på lekeplassen kommer Nils Nettleser tilbake og forteller om alt som skjedde hos supersnill.no. Dette var ikke en trygg lekeplass likevel!
Bente Bruker klikker i vinkel og ringer til supersnill.no for å fortelle om problemene. De mistenker umiddelbart cross-site-scripting-rampestreker og ansetter sporenstreks en tidligere barnehagetante, tante CSP, for å passe på nettleserne.
Bente Bruker sender deretter Nils Nettleser tilbake til supersnill.no, hvor han blir møtt av tante CSP.
“Slapp av lille venn! Jeg skal passe på deg, bare gå og lek du.”
Inne på supersnill.no så treffer Nils Nettleser på et regelskilt. Pliktoppfyllende som han er, så følger han alltid reglene. Han vet ikke at disse reglene er lurt inn av en bølle.
Tante CSP skriker ut og ødelegger de ondsinnede reglene før Nils Nettleser rekker å følge de.
Det tar ikke lang tid før den neste bølla prøver seg på Nils Nettleser. Denne gangen har bølla på et eller annet vis klart å snike inn et bilde fra utsiden.
Nok en gang reagerer tante CSP og fjerner bildene fra bølla.
Ved neste hjørne så venter nok en overraskelse. En bølle har smuglet inn et par med tullebriller på supersnill.no
Nils Nettleser plukker selvsagt opp brillene og tar de på seg.
Tullebrillene endrer fullstendig hvordan supersnill.no ser ut, og det er ikke noe trivelig syn!
Tante CSP har sett dette før! Ingen tullebriller her i gården! Lekeplassen skal se ut akkurat som arkitekten bestemte!
Ok, nå er denne allegorien strukket langt nok. Som dere kan se så kan CSP være et nyttig verktøy.
¶Bare å sette en streng CSP da vel?
Så løsningen her er å sette på en CSP-header på nettsiden din, hvor vanskelig kan vel det være?
Det er dessverre ikke helt rett fram. Hvitelister av godkjente kilder i CSP-headeren er bedre enn ingenting, men ikke trygt nok. Det er for lett å omgå for en angriper.
Hvordan da?
En angriper har mange måter å gjøre det på:
- Snike inn en ondsinnet JavaScript-fil i katalogen hvor nettsiden har JavaScript-filene sine
- Da vil den ondsinnede filen fremstå som om den kommer fra din server
- Kompromittere tredjepart som er hvitelistet i din CSP
- Kanskje serverer du JavaScript via en CDN?
- Kanskje overvåker du brukerne dine med et eksternt analyseverktøy?
- Da kan en angriper snike inn ondsinnet kode enten i den eksterne JavaScripten eller legge til en fil på deres server
Gullstandarden for CSP-headere er i følge OWASP sin CSP Cheat sheet å bruke nonce-mekanismen og/eller hash av javascript-filene i CSP-headeren, men det er ikke så lett å gjennomføre i praksis.
Nonce
Man setter en nonce (dvs verdi som kun brukes én gang) i CSP-headeren, og kun script-tagger som har en korresponderende nonce-verdi vil bli lastet.
Content-Security-Policy: script-src 'nonce-tralala123'
<script nonce="tralalal123">console.log("Dette vil kjøre pga matchende nonce")</script>
<script>console.log("Dette blir blokkert")</script>
Så om en angriper klarer å lure inn en script-tag, så blir den blokkert fordi angriperen ikke klarer å gjette noncen.
Hash
Man kan også begrense hvilke JavaScript-filer som kan lastes ved å hashe innholdet og legge inn hashen i CSP-headeren:
Content-Security-Policy: script-src 'sha256-f5bb70ef3c3bc344ad28811ad60f8282fd8cd85a8e9290022adb5a9b27b1af23'
<script src="fil-med-innhold-som-matcher-hashen-i-csp-header.js" />
Hvis en angriper klarer å lure inn noe JavaScript, så vil nettleseren ignorere det fordi det mangler en hash i CSP-headeren.
¶Er din CSP i orden?
Lar du dine brukere sende sine nettlesere til nettsiden din for å leke uten en tante CSP?
Ta en rask sjekk om dine egne nettsider er beskytta med en Content Security Policy-header. Det er bare å åpne utviklerverktøyet i nettleseren og kikke på respons-headere som ligger på det første HTML-dokumentet som siden din serverer.
Samtidig kan du sjekke hva andre gjør, f.eks:
- banken din
- forsikringsselskapet ditt
- eposttjenesten din
- sosiale medier
- offentlige tjenester du bruker
Noen setter ikke CSP-header i det hele tatt. Andre setter en CSP-header, men lener seg på lange hvitelister. Det er bare i unntakstilfeller at man følger OWASP-anbefalingene med bruk av nonce og/eller hash.
Hvorfor er det slik?
Det lurer jeg også på, men her er en liste med mulige forklaringer:
- Kanskje man vurderer at de andre tiltakene man har mot XSS er gode nok?
- For høy utviklingskostnad
- Hvert eneste script må inkludere en nonce og/eller hash, noe som krever endringer av kode og bygg
- Man bruker tredjepart-script pga brukeranalyse, reklame, sosiale medier etc
- Hvis de endrer seg så må du oppdatere hash
- Hvis scriptene legger til nye script tags dynamisk så må disse også ha nonce. Dette kan løses med å legge til strict-dynamic
- Vanskelig å endre på gamle løsninger
- Hvis man har en legacy-løsning som er utviklet over lang tid uten en CSP-header
- Å stramme til med en streng CSP-header vil føre til at slike løsninger slutter å virke uten større omstruktureringer
¶Hjelp, hva nå?
Vi lever i en skummel verden og internett er ikke noe unntak. Sikkerhet har aldri vært viktigere, spesielt om man er i en utsatt bransje. Cross-Site Scripting (XSS) er høyt oppe på OWASP Top 10, og det bør man ta på alvor.
Merk at Content Security Policy alene ikke er nok for å beskytte mot XSS-angrep, men heller en nyttig del av et større forsvar.
Eksempelvis så er det flere tiltak man bør gjøre i tillegg, her er noen få:
- vaske data fra utsiden
- sikkerhetsmonitorering
- Integritetssjekk av ressurser, spesielt nyttig om man bruker en CDN
React og andre moderne rammeverk vasker dynamisk innhold for deg automatisk, men det er ikke alltid nok. F.eks om du trenger å støtte en rik-tekst-editor eller skal servere dynamisk HTML-innhold fra en database, så er det fort gjort å gå i XSS-fella.
Kanskje du ikke trenger så mye JavaScript på siden din? Angrepsflaten blir mindre ved å bygge løsninger over en enklere lest. Der kan du sjekke Robin sin bloggpost om HTMX, som er i vinden om dagen.
Konklusjon
Det er ikke trivielt å sette en trygg CSP-header. Det krever kunnskap og at man balanserer flere hensyn som f.eks vedlikeholdbarhet og utviklingshastighet. Et godt sted å begynne kan være OWASP sin CSP Cheat sheet.
CSP har også en rapporteringsfunksjon, som man kan bruke for å overvåke brudd på CSP-reglene man har satt. Merk at dette generer en god del støy, f.eks pga nettleser-plugins eller andre falske positiv, men det kan være et nyttig verktøy likevel.
Lykke til!