En omfattende guide til at forbedre frontend-sikkerhed ved hjælp af Content Security Policy (CSP) og Cross-Origin Resource Sharing (CORS), som beskytter dine webapplikationer mod moderne trusler.
Frontend Sikkerhedshærdning: Content Security Policy og CORS
I dagens forbundne digitale landskab er frontend-sikkerhed altafgørende. Webapplikationer bliver i stigende grad mål for sofistikerede angreb, hvilket gør robuste sikkerhedsforanstaltninger essentielle. To kritiske komponenter i en sikker frontend-arkitektur er Content Security Policy (CSP) og Cross-Origin Resource Sharing (CORS). Denne omfattende guide giver et dybdegående kig på disse teknologier og tilbyder praktiske eksempler og handlingsorienterede indsigter for at hjælpe dig med at styrke dine webapplikationer mod moderne trusler.
Hvad er Content Security Policy (CSP)?
Content Security Policy (CSP) er et ekstra sikkerhedslag, der hjælper med at opdage og afbøde visse typer angreb, herunder Cross-Site Scripting (XSS) og datainjektionsangreb. CSP implementeres ved, at webserveren sender en Content-Security-Policy HTTP-svarheader til browseren. Denne header definerer en hvidliste over kilder, som browseren har tilladelse til at indlæse ressourcer fra. Ved at begrænse kilderne til indhold, som en browser kan indlæse, gør CSP det betydeligt sværere for angribere at injicere ondsindet kode på din hjemmeside.
Hvordan CSP fungerer
CSP fungerer ved at instruere browseren i kun at indlæse ressourcer (f.eks. scripts, stylesheets, billeder, skrifttyper) fra godkendte kilder. Disse kilder specificeres i CSP-headeren ved hjælp af direktiver. Hvis en browser forsøger at indlæse en ressource fra en kilde, der ikke er eksplicit tilladt, vil den blokere anmodningen og rapportere en overtrædelse.
CSP-direktiver: En omfattende oversigt
CSP-direktiver styrer de typer ressourcer, der kan indlæses fra specifikke kilder. Her er en oversigt over nogle af de vigtigste direktiver:
- default-src: Angiver standardkilden for alle indholdstyper. Dette er et fallback-direktiv, der gælder, når andre, mere specifikke direktiver ikke er til stede.
- script-src: Angiver de kilder, hvorfra scripts kan indlæses. Dette er afgørende for at forhindre XSS-angreb.
- style-src: Angiver de kilder, hvorfra stylesheets kan indlæses.
- img-src: Angiver de kilder, hvorfra billeder kan indlæses.
- font-src: Angiver de kilder, hvorfra skrifttyper kan indlæses.
- media-src: Angiver de kilder, hvorfra lyd og video kan indlæses.
- object-src: Angiver de kilder, hvorfra plugins (f.eks. Flash) kan indlæses. Dette er ofte sat til 'none' for helt at deaktivere plugins på grund af deres iboende sikkerhedsrisici.
- frame-src: Angiver de kilder, hvorfra frames (f.eks. <iframe>) kan indlæses.
- connect-src: Angiver de URL'er, som brugeragenten kan oprette forbindelse til ved hjælp af script-grænseflader som XMLHttpRequest, WebSocket og EventSource.
- base-uri: Angiver de URL'er, der kan bruges i et dokuments <base>-element.
- form-action: Angiver de URL'er, hvortil formularafsendelser kan sendes.
- upgrade-insecure-requests: Instruerer brugeragenten til automatisk at opgradere usikre anmodninger (HTTP) til sikre anmodninger (HTTPS).
- report-uri: Angiver en URL, hvor browseren skal sende rapporter om CSP-overtrædelser. Dette direktiv er forældet til fordel for `report-to`.
- report-to: Angiver et rapporteringsgruppenavn defineret i `Report-To`-headeren, hvortil browseren skal sende rapporter om CSP-overtrædelser.
Nøgleord for CSP-kildelister
Inden for CSP-direktiver kan du bruge nøgleord for kildelister til at definere tilladte kilder. Her er nogle almindelige nøgleord:
- 'self': Tillader ressourcer fra samme oprindelse (skema og host) som dokumentet.
- 'none': Tillader ikke ressourcer fra nogen kilder.
- 'unsafe-inline': Tillader brugen af inline scripts og styles (f.eks. <script>-tags og style-attributter). Brug med ekstrem forsigtighed, da det svækker CSP-beskyttelsen mod XSS betydeligt.
- 'unsafe-eval': Tillader brugen af dynamiske kodeevalueringsfunktioner som
eval()ogFunction(). Brug med ekstrem forsigtighed, da det introducerer betydelige sikkerhedsrisici. - 'unsafe-hashes': Tillader specifikke inline event-handlere eller <style>-tags, der matcher en specificeret hash. Kræver browser-understøttelse. Brug med forsigtighed.
- 'strict-dynamic': Angiver, at den tillid, der eksplicit er givet til et script til stede i markuppen, ved at ledsage det med en nonce eller hash, skal udbredes til alle de scripts, der indlæses af det pågældende rod-script.
- data: Tillader data: URI'er (f.eks. inline billeder kodet som base64). Brug med forsigtighed.
- https:: Tillader, at ressourcer indlæses over HTTPS fra ethvert domæne.
- [hostname]: Tillader ressourcer fra et specifikt domæne (f.eks. example.com). Du kan også angive et portnummer (f.eks. example.com:8080).
- [scheme]://[hostname]:[port]: En fuldt kvalificeret URI, der tillader ressourcer fra det specificerede skema, host og port.
Praktiske CSP-eksempler
Lad os se på nogle praktiske eksempler på CSP-headere:
Eksempel 1: Grundlæggende CSP med 'self'
Denne politik tillader kun ressourcer fra samme oprindelse:
Content-Security-Policy: default-src 'self'
Eksempel 2: Tilladelse af scripts fra et specifikt domæne
Denne politik tillader scripts fra dit eget domæne og et betroet CDN:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Eksempel 3: Deaktivering af inline scripts og styles
Denne politik tillader ikke inline scripts og styles, hvilket er et stærkt forsvar mod XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Vigtigt: Deaktivering af inline scripts kræver, at du refaktorerer din HTML for at flytte inline scripts til eksterne filer.
Eksempel 4: Brug af Nonces for inline scripts
Hvis du er nødt til at bruge inline scripts, skal du bruge nonces (kryptografisk tilfældige engangstokens) til at hvidliste specifikke inline script-blokke. Dette er mere sikkert end 'unsafe-inline'. Serveren skal generere en unik nonce for hver anmodning og inkludere den i både CSP-headeren og <script>-tagget.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Bemærk: Husk at generere en ny nonce for hver anmodning. Genbrug ikke nonces!
Eksempel 5: Brug af Hashes for inline styles
Ligesom nonces kan hashes bruges til at hvidliste specifikke inline <style>-blokke. Dette gøres ved at generere en SHA256-, SHA384- eller SHA512-hash af stilindholdet.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Bemærk: Hashes er mindre fleksible end nonces, da enhver ændring af stilindholdet vil ugyldiggøre hashen.
Eksempel 6: Rapportering af CSP-overtrædelser
For at overvåge CSP-overtrædelser skal du bruge report-uri- eller report-to-direktivet:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Du skal også konfigurere Report-To-headeren. Report-To-headeren definerer en eller flere rapporteringsgrupper, som specificerer, hvor og hvordan rapporter skal sendes.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Test og implementering af CSP
Implementering af CSP kræver omhyggelig planlægning og test. Start med en restriktiv politik og løsn den gradvist efter behov. Brug Content-Security-Policy-Report-Only-headeren til at teste din politik uden at blokere ressourcer. Denne header rapporterer overtrædelser uden at håndhæve politikken, hvilket giver dig mulighed for at identificere og rette problemer, før du implementerer politikken i produktion.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analyser de rapporter, der genereres af browseren, for at identificere eventuelle overtrædelser og justere din politik i overensstemmelse hermed. Når du er sikker på, at din politik fungerer korrekt, skal du implementere den ved hjælp af Content-Security-Policy-headeren.
Bedste praksis for CSP
- Start med en default-src: Definer altid en
default-srcfor at etablere en grundlæggende politik. - Vær specifik: Brug specifikke direktiver og nøgleord for kildelister til at begrænse omfanget af din politik.
- Undgå 'unsafe-inline' og 'unsafe-eval': Disse nøgleord svækker CSP betydeligt og bør undgås, når det er muligt.
- Brug nonces eller hashes for inline scripts og styles: Hvis du skal bruge inline scripts eller styles, skal du bruge nonces eller hashes til at hvidliste specifikke kodeblokke.
- Overvåg CSP-overtrædelser: Brug
report-uri- ellerreport-to-direktivet til at overvåge CSP-overtrædelser og justere din politik i overensstemmelse hermed. - Test grundigt: Brug
Content-Security-Policy-Report-Only-headeren til at teste din politik, før du implementerer den i produktion. - Iterer og finpuds: CSP er ikke en engangskonfiguration. Overvåg og finpuds løbende din politik for at tilpasse dig ændringer i din applikation og trusselslandskabet.
Hvad er Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) er en mekanisme, der tillader websider fra én oprindelse (domæne) at få adgang til ressourcer fra en anden oprindelse. Som standard håndhæver browsere en Same-Origin Policy, som forhindrer scripts i at foretage anmodninger til en anden oprindelse end den, scriptet stammer fra. CORS giver en måde selektivt at lempe denne begrænsning på, hvilket tillader legitime cross-origin-anmodninger, mens man beskytter mod ondsindede angreb.
Forståelse af Same-Origin Policy
Same-Origin Policy er en fundamental sikkerhedsmekanisme, der forhindrer et ondsindet script fra en hjemmeside i at få adgang til følsomme data på en anden hjemmeside. En oprindelse er defineret af skemaet (protokol), host (domæne) og port. To URL'er har samme oprindelse, hvis og kun hvis de har samme skema, host og port.
For eksempel:
https://www.example.com/app1/index.htmloghttps://www.example.com/app2/index.htmlhar samme oprindelse.https://www.example.com/index.htmloghttp://www.example.com/index.htmlhar forskellige oprindelser (forskelligt skema).https://www.example.com/index.htmloghttps://sub.example.com/index.htmlhar forskellige oprindelser (forskellig host).https://www.example.com:8080/index.htmloghttps://www.example.com:80/index.htmlhar forskellige oprindelser (forskellig port).
Hvordan CORS fungerer
Når en webside foretager en cross-origin-anmodning, sender browseren først en "preflight"-anmodning til serveren. Preflight-anmodningen bruger HTTP OPTIONS-metoden og inkluderer headere, der angiver HTTP-metoden og de headere, som den faktiske anmodning vil bruge. Serveren svarer derefter med headere, der angiver, om cross-origin-anmodningen er tilladt.
Hvis serveren tillader anmodningen, inkluderer den Access-Control-Allow-Origin-headeren i svaret. Denne header specificerer den eller de oprindelser, der har tilladelse til at få adgang til ressourcen. Browseren fortsætter derefter med den faktiske anmodning. Hvis serveren ikke tillader anmodningen, inkluderer den ikke Access-Control-Allow-Origin-headeren, og browseren blokerer anmodningen.
CORS-headere: Et detaljeret kig
CORS er afhængig af HTTP-headere til at kommunikere mellem browseren og serveren. Her er de vigtigste CORS-headere:
- Access-Control-Allow-Origin: Angiver den eller de oprindelser, der har tilladelse til at få adgang til ressourcen. Denne header kan indeholde en specifik oprindelse (f.eks.
https://www.example.com), en wildcard (*) ellernull. Brug af*tillader anmodninger fra enhver oprindelse, hvilket generelt ikke anbefales af sikkerhedsmæssige årsager. Brug af `null` er kun passende for "opaque-svar", som f.eks. når ressourcen hentes ved hjælp af `file://`-protokollen eller en data-URI. - Access-Control-Allow-Methods: Angiver de HTTP-metoder, der er tilladt for cross-origin-anmodningen (f.eks.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Angiver de HTTP-headere, der er tilladt i cross-origin-anmodningen. Dette er vigtigt for håndtering af brugerdefinerede headere.
- Access-Control-Allow-Credentials: Angiver, om browseren skal inkludere legitimationsoplysninger (f.eks. cookies, autorisationsheadere) i cross-origin-anmodningen. Denne header skal være sat til
truefor at tillade legitimationsoplysninger. - Access-Control-Expose-Headers: Angiver, hvilke headere der kan eksponeres for klienten. Som standard er kun et begrænset sæt headere eksponeret.
- Access-Control-Max-Age: Angiver den maksimale tid (i sekunder), som browseren kan cache preflight-anmodningen.
- Origin: Dette er en anmodningsheader sendt af browseren for at angive anmodningens oprindelse.
- Vary: En generel HTTP-header, men vigtig for CORS. Når `Access-Control-Allow-Origin` genereres dynamisk, bør `Vary: Origin`-headeren inkluderes i svaret for at instruere caching-mekanismer om, at svaret varierer baseret på `Origin`-anmodningsheaderen.
Praktiske CORS-eksempler
Lad os se på nogle praktiske eksempler på CORS-konfigurationer:
Eksempel 1: Tilladelse af anmodninger fra en specifik oprindelse
Denne konfiguration tillader kun anmodninger fra https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Eksempel 2: Tilladelse af anmodninger fra enhver oprindelse (anbefales ikke)
Denne konfiguration tillader anmodninger fra enhver oprindelse. Brug med forsigtighed, da det kan introducere sikkerhedsrisici:
Access-Control-Allow-Origin: *
Eksempel 3: Tilladelse af specifikke metoder og headere
Denne konfiguration tillader GET-, POST- og PUT-metoder samt Content-Type- og Authorization-headerne:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Eksempel 4: Tilladelse af legitimationsoplysninger
For at tillade legitimationsoplysninger (f.eks. cookies) skal du sætte Access-Control-Allow-Credentials til true og angive en specifik oprindelse (du kan ikke bruge *, når du tillader legitimationsoplysninger):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Du skal også sætte credentials: 'include' i din JavaScript fetch/XMLHttpRequest-anmodning.
fetch('https://api.example.com/data', {
credentials: 'include'
})
CORS Preflight-anmodninger
For visse typer cross-origin-anmodninger (f.eks. anmodninger med brugerdefinerede headere eller andre metoder end GET, HEAD eller POST med Content-Type af application/x-www-form-urlencoded, multipart/form-data eller text/plain), sender browseren en preflight-anmodning ved hjælp af OPTIONS-metoden. Serveren skal svare på preflight-anmodningen med de passende CORS-headere for at angive, om den faktiske anmodning er tilladt.
Her er et eksempel på en preflight-anmodning og -svar:
Preflight-anmodning (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-headeren angiver, hvor længe browseren kan cache preflight-svaret, hvilket reducerer antallet af preflight-anmodninger.
CORS og JSONP
JSON with Padding (JSONP) er en ældre teknik til at omgå Same-Origin Policy. JSONP har dog betydelige sikkerhedsrisici og bør undgås til fordel for CORS. JSONP er afhængig af at injicere <script>-tags på siden, hvilket kan eksekvere vilkårlig kode. CORS giver en mere sikker og fleksibel måde at håndtere cross-origin-anmodninger på.
Bedste praksis for CORS
- Undgå at bruge *: Undgå at bruge wildcard'et (*) i
Access-Control-Allow-Origin-headeren, da det tillader anmodninger fra enhver oprindelse. Angiv i stedet den eller de specifikke oprindelser, der har tilladelse til at få adgang til ressourcen. - Vær specifik med metoder og headere: Angiv de nøjagtige HTTP-metoder og headere, der er tilladt i
Access-Control-Allow-Methods- ogAccess-Control-Allow-Headers-headerne. - Brug Access-Control-Allow-Credentials med forsigtighed: Aktivér kun
Access-Control-Allow-Credentials, hvis du har brug for at tillade legitimationsoplysninger (f.eks. cookies) i cross-origin-anmodninger. Vær opmærksom på de sikkerhedsmæssige konsekvenser af at tillade legitimationsoplysninger. - Sikr dine preflight-anmodninger: Sørg for, at din server håndterer preflight-anmodninger korrekt og returnerer de korrekte CORS-headere.
- Brug HTTPS: Brug altid HTTPS for både oprindelsen og de ressourcer, du tilgår cross-origin. Dette hjælper med at beskytte mod man-in-the-middle-angreb.
- Vary: Origin: Hvis du dynamisk genererer `Access-Control-Allow-Origin`-headeren, skal du altid inkludere `Vary: Origin`-headeren for at forhindre caching-problemer.
CSP og CORS i praksis: En kombineret tilgang
Selvom både CSP og CORS adresserer sikkerhedsproblemer, opererer de på forskellige lag og giver komplementær beskyttelse. CSP fokuserer på at forhindre browseren i at indlæse ondsindet indhold, mens CORS fokuserer på at kontrollere, hvilke oprindelser der kan få adgang til ressourcer på din server.
Ved at kombinere CSP og CORS kan du skabe en mere robust sikkerhedsposition for dine webapplikationer. For eksempel kan du bruge CSP til at begrænse de kilder, hvorfra scripts kan indlæses, og CORS til at kontrollere, hvilke oprindelser der kan få adgang til dine API-endepunkter.
Eksempel: Sikring af en API med CSP og CORS
Lad os sige, du har en API hostet på https://api.example.com, som du kun ønsker skal være tilgængelig fra https://www.example.com. Du kan konfigurere din server til at returnere følgende headere:
API-svarheadere (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
Og du kan konfigurere din hjemmeside (https://www.example.com) til at bruge følgende CSP-header:
Hjemmesidens CSP-header (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Denne CSP-politik tillader hjemmesiden at indlæse scripts og oprette forbindelse til API'en, men forhindrer den i at indlæse scripts fra eller oprette forbindelse til andre domæner.
Konklusion
Content Security Policy (CSP) og Cross-Origin Resource Sharing (CORS) er essentielle værktøjer til at hærde sikkerheden i dine frontend-applikationer. Ved omhyggeligt at konfigurere CSP og CORS kan du markant reducere risikoen for XSS-angreb, datainjektionsangreb og andre sikkerhedssårbarheder. Husk at starte med en restriktiv politik, teste grundigt og løbende overvåge og finpudse din konfiguration for at tilpasse dig ændringer i din applikation og det udviklende trusselslandskab. Ved at prioritere frontend-sikkerhed kan du beskytte dine brugere og sikre integriteten af dine webapplikationer i dagens stadig mere komplekse digitale verden.