En omfattende guide til å forbedre frontend-sikkerhet med Content Security Policy (CSP) og Cross-Origin Resource Sharing (CORS) for å beskytte nettapplikasjoner mot moderne trusler.
Frontend-sikkerhetsherding: Content Security Policy og CORS
I dagens sammenkoblede digitale landskap er frontend-sikkerhet av største betydning. Nettapplikasjoner blir i økende grad utsatt for sofistikerte angrep, noe som gjør robuste sikkerhetstiltak avgjørende. To kritiske komponenter i en sikker frontend-arkitektur er Content Security Policy (CSP) og Cross-Origin Resource Sharing (CORS). Denne omfattende guiden gir en grundig gjennomgang av disse teknologiene, med praktiske eksempler og handlingsrettet innsikt for å hjelpe deg med å styrke nettapplikasjonene dine mot moderne trusler.
Hva er Content Security Policy (CSP)?
Content Security Policy (CSP) er et ekstra sikkerhetslag som hjelper til med å oppdage og redusere visse typer angrep, inkludert Cross-Site Scripting (XSS) og datainjeksjonsangrep. CSP implementeres ved at webserveren sender en Content-Security-Policy HTTP-responshode til nettleseren. Denne hodefeltet definerer en hviteliste over kilder som nettleseren har lov til å laste ressurser fra. Ved å begrense kildene til innhold som en nettleser kan laste, gjør CSP det betydelig vanskeligere for angripere å injisere ondsinnet kode på nettstedet ditt.
Hvordan CSP fungerer
CSP fungerer ved å instruere nettleseren til kun å laste ressurser (f.eks. skript, stilark, bilder, fonter) fra godkjente kilder. Disse kildene spesifiseres i CSP-hodefeltet ved hjelp av direktiver. Hvis en nettleser forsøker å laste en ressurs fra en kilde som ikke er eksplisitt tillatt, vil den blokkere forespørselen og rapportere et brudd.
CSP-direktiver: En omfattende oversikt
CSP-direktiver kontrollerer hvilke typer ressurser som kan lastes fra spesifikke kilder. Her er en oversikt over noen av de viktigste direktivene:
- default-src: Spesifiserer standardkilden for alle innholdstyper. Dette er et reserve-direktiv som gjelder når andre, mer spesifikke direktiver ikke er til stede.
- script-src: Spesifiserer kildene som skript kan lastes fra. Dette er avgjørende for å forhindre XSS-angrep.
- style-src: Spesifiserer kildene som stilark kan lastes fra.
- img-src: Spesifiserer kildene som bilder kan lastes fra.
- font-src: Spesifiserer kildene som fonter kan lastes fra.
- media-src: Spesifiserer kildene som lyd og video kan lastes fra.
- object-src: Spesifiserer kildene som plugins (f.eks. Flash) kan lastes fra. Dette settes ofte til 'none' for å deaktivere plugins helt på grunn av deres iboende sikkerhetsrisikoer.
- frame-src: Spesifiserer kildene som rammer (f.eks. <iframe>) kan lastes fra.
- connect-src: Spesifiserer URL-ene som brukeragenten kan koble til ved hjelp av skriptgrensesnitt som XMLHttpRequest, WebSocket og EventSource.
- base-uri: Spesifiserer URL-ene som kan brukes i et dokuments <base>-element.
- form-action: Spesifiserer URL-ene som skjemainnsendinger kan sendes til.
- upgrade-insecure-requests: Instruerer brukeragenten til å automatisk oppgradere usikre forespørsler (HTTP) til sikre forespørsler (HTTPS).
- report-uri: Spesifiserer en URL dit nettleseren skal sende rapporter om CSP-brudd. Dette direktivet er avviklet til fordel for `report-to`.
- report-to: Spesifiserer et rapporteringsgruppenavn definert i `Report-To`-hodefeltet, dit nettleseren skal sende rapporter om CSP-brudd.
Nøkkelord for kildelister i CSP
Innenfor CSP-direktiver kan du bruke nøkkelord for kildelister for å definere tillatte kilder. Her er noen vanlige nøkkelord:
- 'self': Tillater ressurser fra samme opprinnelse (skjema og vert) som dokumentet.
- 'none': Tillater ikke ressurser fra noen kilder.
- 'unsafe-inline': Tillater bruk av inline-skript og -stiler (f.eks. <script>-tagger og stilattributter). Bruk med ekstrem forsiktighet da det betydelig svekker CSP-beskyttelsen mot XSS.
- 'unsafe-eval': Tillater bruk av dynamiske kodeevalueringsfunksjoner som
eval()ogFunction(). Bruk med ekstrem forsiktighet da det introduserer betydelige sikkerhetsrisikoer. - 'unsafe-hashes': Tillater spesifikke inline hendelseshåndterere eller <style>-tagger som samsvarer med en spesifisert hash. Krever nettleserstøtte. Bruk med forsiktighet.
- 'strict-dynamic': Spesifiserer at tilliten som eksplisitt er gitt til et skript i markeringen, ved å ledsage det med en nonce eller hash, skal forplante seg til alle skriptene som lastes av det rotskriptet.
- data: Tillater data: URI-er (f.eks. inline-bilder kodet som base64). Bruk med forsiktighet.
- https:: Tillater at ressurser lastes over HTTPS fra hvilket som helst domene.
- [hostname]: Tillater ressurser fra et spesifikt domene (f.eks. example.com). Du kan også spesifisere et portnummer (f.eks. example.com:8080).
- [scheme]://[hostname]:[port]: En fullt kvalifisert URI, som tillater ressurser fra det spesifiserte skjemaet, verten og porten.
Praktiske CSP-eksempler
La oss se på noen praktiske eksempler på CSP-hodefelt:
Eksempel 1: Grunnleggende CSP med 'self'
Denne policyen tillater ressurser kun fra samme opprinnelse:
Content-Security-Policy: default-src 'self'
Eksempel 2: Tillate skript fra et spesifikt domene
Denne policyen tillater skript fra ditt eget domene og en pålitelig CDN:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Eksempel 3: Deaktivere inline-skript og -stiler
Denne policyen tillater ikke inline-skript og -stiler, noe som er et sterkt forsvar mot XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Viktig: Deaktivering av inline-skript krever at du refaktorerer HTML-koden din for å flytte inline-skript til eksterne filer.
Eksempel 4: Bruke nonces for inline-skript
Hvis du må bruke inline-skript, bruk nonces (kryptografisk tilfeldige engangstokener) for å hviteliste spesifikke inline-skriptblokker. Dette er sikrere enn 'unsafe-inline'. Serveren må generere en unik nonce for hver forespørsel og inkludere den i både CSP-hodefeltet og <script>-taggen.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Merk: Husk å generere en ny nonce for hver forespørsel. Ikke gjenbruk nonces!
Eksempel 5: Bruke hasher for inline-stiler
I likhet med nonces kan hasher brukes til å hviteliste spesifikke inline <style>-blokker. Dette gjøres ved å generere en SHA256-, SHA384- eller SHA512-hash av stilinnholdet.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Merk: Hasher er mindre fleksible enn nonces, da enhver endring i stilinnholdet vil ugyldiggjøre hashen.
Eksempel 6: Rapportering av CSP-brudd
For å overvåke CSP-brudd, bruk report-uri- eller report-to-direktivet:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Du må også konfigurere Report-To-hodefeltet. Report-To-hodefeltet definerer en eller flere rapporteringsgrupper, som spesifiserer hvor og hvordan rapporter skal sendes.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Testing og distribusjon av CSP
Implementering av CSP krever nøye planlegging og testing. Start med en restriktiv policy og løsne den gradvis etter behov. Bruk Content-Security-Policy-Report-Only-hodefeltet for å teste policyen din uten å blokkere ressurser. Dette hodefeltet rapporterer brudd uten å håndheve policyen, slik at du kan identifisere og fikse problemer før du distribuerer policyen i produksjon.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analyser rapportene som genereres av nettleseren for å identifisere eventuelle brudd og juster policyen din deretter. Når du er trygg på at policyen din fungerer korrekt, distribuerer du den ved hjelp av Content-Security-Policy-hodefeltet.
Beste praksis for CSP
- Start med en default-src: Definer alltid en
default-srcfor å etablere en grunnleggende policy. - Vær spesifikk: Bruk spesifikke direktiver og nøkkelord for kildelister for å begrense omfanget av policyen din.
- Unngå 'unsafe-inline' og 'unsafe-eval': Disse nøkkelordene svekker CSP betydelig og bør unngås når det er mulig.
- Bruk nonces eller hasher for inline-skript og -stiler: Hvis du må bruke inline-skript eller -stiler, bruk nonces eller hasher for å hviteliste spesifikke kodeblokker.
- Overvåk CSP-brudd: Bruk
report-uri- ellerreport-to-direktivet for å overvåke CSP-brudd og juster policyen din deretter. - Test grundig: Bruk
Content-Security-Policy-Report-Only-hodefeltet for å teste policyen din før du distribuerer den i produksjon. - Iterer og forbedre: CSP er ikke en engangskonfigurasjon. Overvåk og forbedre policyen din kontinuerlig for å tilpasse deg endringer i applikasjonen din og trusselbildet.
Hva er Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) er en mekanisme som lar nettsider fra en opprinnelse (domene) få tilgang til ressurser fra en annen opprinnelse. Som standard håndhever nettlesere en Same-Origin Policy, som forhindrer skript i å gjøre forespørsler til en annen opprinnelse enn den skriptet kom fra. CORS gir en måte å selektivt lempe på denne begrensningen, slik at legitime forespørsler på tvers av opprinnelser tillates, samtidig som det beskyttes mot ondsinnede angrep.
Forstå Same-Origin Policy
Same-Origin Policy er en grunnleggende sikkerhetsmekanisme som forhindrer et ondsinnet skript fra ett nettsted i å få tilgang til sensitive data på et annet nettsted. En opprinnelse er definert av skjemaet (protokoll), verten (domene) og porten. To URL-er har samme opprinnelse hvis og bare hvis de har samme skjema, vert og port.
For eksempel:
https://www.example.com/app1/index.htmloghttps://www.example.com/app2/index.htmlhar samme opprinnelse.https://www.example.com/index.htmloghttp://www.example.com/index.htmlhar forskjellig opprinnelse (forskjellig skjema).https://www.example.com/index.htmloghttps://sub.example.com/index.htmlhar forskjellig opprinnelse (forskjellig vert).https://www.example.com:8080/index.htmloghttps://www.example.com:80/index.htmlhar forskjellig opprinnelse (forskjellig port).
Hvordan CORS fungerer
Når en nettside gjør en forespørsel på tvers av opprinnelser, sender nettleseren først en "preflight"-forespørsel til serveren. Preflight-forespørselen bruker HTTP OPTIONS-metoden og inkluderer hodefelt som indikerer HTTP-metoden og hodefeltene som den faktiske forespørselen vil bruke. Serveren svarer deretter med hodefelt som indikerer om forespørselen på tvers av opprinnelser er tillatt.
Hvis serveren tillater forespørselen, inkluderer den Access-Control-Allow-Origin-hodefeltet i svaret. Dette hodefeltet spesifiserer opprinnelsen(e) som har lov til å få tilgang til ressursen. Nettleseren fortsetter deretter med den faktiske forespørselen. Hvis serveren ikke tillater forespørselen, inkluderer den ikke Access-Control-Allow-Origin-hodefeltet, og nettleseren blokkerer forespørselen.
CORS-headere: En detaljert gjennomgang
CORS er avhengig av HTTP-hodefelt for å kommunisere mellom nettleseren og serveren. Her er de viktigste CORS-hodefeltene:
- Access-Control-Allow-Origin: Spesifiserer opprinnelsen(e) som har lov til å få tilgang til ressursen. Dette hodefeltet kan inneholde en spesifikk opprinnelse (f.eks.
https://www.example.com), en joker (*), ellernull. Bruk av*tillater forespørsler fra enhver opprinnelse, noe som generelt ikke anbefales av sikkerhetsgrunner. Bruk av `null` er kun passende for "ugjennomsiktige svar" som når ressursen hentes med `file://`-protokollen eller en data-URI. - Access-Control-Allow-Methods: Spesifiserer HTTP-metodene som er tillatt for forespørselen på tvers av opprinnelser (f.eks.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Spesifiserer HTTP-hodefeltene som er tillatt i forespørselen på tvers av opprinnelser. Dette er viktig for å håndtere egendefinerte hodefelt.
- Access-Control-Allow-Credentials: Indikerer om nettleseren skal inkludere legitimasjon (f.eks. informasjonskapsler, autorisasjonshoder) i forespørselen på tvers av opprinnelser. Dette hodefeltet må settes til
truefor å tillate legitimasjon. - Access-Control-Expose-Headers: Spesifiserer hvilke hodefelt som kan eksponeres for klienten. Som standard er bare et begrenset sett med hodefelt eksponert.
- Access-Control-Max-Age: Spesifiserer den maksimale tiden (i sekunder) nettleseren kan bufre preflight-forespørselen.
- Origin: Dette er et forespørselshode sendt av nettleseren for å indikere opprinnelsen til forespørselen.
- Vary: Et generelt HTTP-hodefelt, men viktig for CORS. Når `Access-Control-Allow-Origin` genereres dynamisk, bør `Vary: Origin`-hodefeltet inkluderes i svaret for å instruere bufringsmekanismer om at svaret varierer basert på `Origin`-forespørselshodet.
Praktiske CORS-eksempler
La oss se på noen praktiske eksempler på CORS-konfigurasjoner:
Eksempel 1: Tillate forespørsler fra en spesifikk opprinnelse
Denne konfigurasjonen tillater forespørsler kun fra https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Eksempel 2: Tillate forespørsler fra enhver opprinnelse (ikke anbefalt)
Denne konfigurasjonen tillater forespørsler fra enhver opprinnelse. Bruk med forsiktighet da det kan introdusere sikkerhetsrisikoer:
Access-Control-Allow-Origin: *
Eksempel 3: Tillate spesifikke metoder og hodefelt
Denne konfigurasjonen tillater GET-, POST- og PUT-metoder, og Content-Type- og Authorization-hodefeltene:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Eksempel 4: Tillate legitimasjon
For å tillate legitimasjon (f.eks. informasjonskapsler), må du sette Access-Control-Allow-Credentials til true og spesifisere en spesifikk opprinnelse (du kan ikke bruke * når du tillater legitimasjon):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Du må også sette credentials: 'include' i din JavaScript fetch/XMLHttpRequest-forespørsel.
fetch('https://api.example.com/data', {
credentials: 'include'
})
CORS Preflight-forespørsler
For visse typer forespørsler på tvers av opprinnelser (f.eks. forespørsler med egendefinerte hodefelt eller andre metoder enn GET, HEAD eller POST med Content-Type av application/x-www-form-urlencoded, multipart/form-data, eller text/plain), sender nettleseren en preflight-forespørsel med OPTIONS-metoden. Serveren må svare på preflight-forespørselen med de riktige CORS-hodefeltene for å indikere om den faktiske forespørselen er tillatt.
Her er et eksempel på en preflight-forespørsel og et svar:
Preflight-forespørsel (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Preflight-svar (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Access-Control-Max-Age-hodefeltet spesifiserer hvor lenge nettleseren kan bufre preflight-svaret, noe som reduserer antall preflight-forespørsler.
CORS og JSONP
JSON with Padding (JSONP) er en eldre teknikk for å omgå Same-Origin Policy. JSONP har imidlertid betydelige sikkerhetsrisikoer og bør unngås til fordel for CORS. JSONP er avhengig av å injisere <script>-tagger på siden, som kan utføre vilkårlig kode. CORS gir en sikrere og mer fleksibel måte å håndtere forespørsler på tvers av opprinnelser.
Beste praksis for CORS
- Unngå å bruke *: Unngå å bruke jokeren (*) i
Access-Control-Allow-Origin-hodefeltet, da det tillater forespørsler fra enhver opprinnelse. Spesifiser i stedet den eller de spesifikke opprinnelsene som har lov til å få tilgang til ressursen. - Vær spesifikk med metoder og hodefelt: Spesifiser de nøyaktige HTTP-metodene og hodefeltene som er tillatt i
Access-Control-Allow-Methods- ogAccess-Control-Allow-Headers-hodefeltene. - Bruk Access-Control-Allow-Credentials med forsiktighet: Aktiver kun
Access-Control-Allow-Credentialshvis du trenger å tillate legitimasjon (f.eks. informasjonskapsler) i forespørsler på tvers av opprinnelser. Vær klar over sikkerhetsimplikasjonene av å tillate legitimasjon. - Sikre dine preflight-forespørsler: Sørg for at serveren din håndterer preflight-forespørsler riktig og returnerer de korrekte CORS-hodefeltene.
- Bruk HTTPS: Bruk alltid HTTPS for både opprinnelsen og ressursene du får tilgang til på tvers av opprinnelser. Dette hjelper med å beskytte mot man-in-the-middle-angrep.
- Vary: Origin: Hvis du genererer `Access-Control-Allow-Origin`-hodefeltet dynamisk, inkluder alltid `Vary: Origin`-hodefeltet for å forhindre bufringsproblemer.
CSP og CORS i praksis: En kombinert tilnærming
Selv om både CSP og CORS adresserer sikkerhetshensyn, opererer de på forskjellige lag og gir komplementær beskyttelse. CSP fokuserer på å forhindre at nettleseren laster ondsinnet innhold, mens CORS fokuserer på å kontrollere hvilke opprinnelser som kan få tilgang til ressurser på serveren din.
Ved å kombinere CSP og CORS kan du skape en mer robust sikkerhetspositur for nettapplikasjonene dine. For eksempel kan du bruke CSP til å begrense kildene som skript kan lastes fra, og CORS til å kontrollere hvilke opprinnelser som kan få tilgang til API-endepunktene dine.
Eksempel: Sikring av et API med CSP og CORS
La oss si at du har et API hostet på https://api.example.com som du vil at kun skal være tilgjengelig fra https://www.example.com. Du kan konfigurere serveren din til å returnere følgende hodefelt:
API-svarhoder (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
Og du kan konfigurere nettstedet ditt (https://www.example.com) til å bruke følgende CSP-hodefelt:
Nettstedets CSP-hode (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Denne CSP-policyen tillater nettstedet å laste skript og koble til API-et, men forhindrer det i å laste skript eller koble til andre domener.
Konklusjon
Content Security Policy (CSP) og Cross-Origin Resource Sharing (CORS) er essensielle verktøy for å herde sikkerheten til frontend-applikasjonene dine. Ved å konfigurere CSP og CORS nøye kan du betydelig redusere risikoen for XSS-angrep, datainjeksjonsangrep og andre sikkerhetssårbarheter. Husk å starte med en restriktiv policy, teste grundig, og kontinuerlig overvåke og forbedre konfigurasjonen din for å tilpasse deg endringer i applikasjonen din og det utviklende trusselbildet. Ved å prioritere frontend-sikkerhet kan du beskytte brukerne dine og sikre integriteten til nettapplikasjonene dine i dagens stadig mer komplekse digitale verden.