# Content Security Policy

## Vad det är

Content Security Policy är en uppsättning regler som en webbplats lämnar till
webbläsaren om vad dess sidor får köra, hämta och skicka, och som webbläsaren
sedan upprätthåller för webbplatsens räkning. Namnet förkortas nästan alltid
CSP. Webbplatsen skickar reglerna i svarsheadern `Content-Security-Policy`,
eller skriver in dem i sidan i ett `meta`-element, och från det ögonblicket
stoppas varje skript, stilmall, bild, typsnitt, ram eller anslutning som
reglerna inte tillåter innan det hinner laddas.

En policy är en kort sträng av direktiv åtskilda med semikolon. Varje direktiv
namnger ett slags resurs eller beteende och de källor som det godtar. En strikt
policy ser ut så här, med ett direktiv per rad för läsbarhetens skull, fast den
i trafiken är ett enda headervärde:

```text
default-src 'self';
script-src 'nonce-q8Zt3VwR1mKx7NpL2cYfJA==' 'strict-dynamic';
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'none'
```

Vokabulären är liten. `'self'` betyder sidans eget ursprung. En källa med
värdnamn, som `https://static.example.com`, eller en protokolldel som `https:`
vidgar det. `'none'` tillåter ingenting. En nonce är ett slumpvärde som servern
tar fram för ett enda svar och skriver både i policyn och på varje skriptelement
som den går i god för. En hash är det kryptografiska avtrycket av ett
inline-skripts exakta text, så att just det skriptet och inget annat får köras.
Två nyckelord, `'unsafe-inline'` och `'unsafe-eval'`, slår av skydden igen, och
deras namn är en rättvis varning.

`default-src` fungerar som reserv för de hämtningsdirektiv som en policy
utelämnar, t.ex. `script-src`, `style-src`, `img-src` och `connect-src`. Det
gäller bara för dem. Direktiv som styr beteende snarare än hämtning, bl.a.
`base-uri`, `form-action` och `frame-ancestors`, förblir obegränsade om de inte
skrivs ut.

En policy kan också köras i ett bevakande läge. Skickad som
`Content-Security-Policy-Report-Only` blockerar den ingenting och rapporterar i
stället varje överträdelse till en mottagare som namnges med `report-to`, som
använder webbläsarens Reporting API. Det äldre direktivet `report-uri` är
föråldrat till förmån för det. Den aktuella texten i standarden är Content
Security Policy Level 3, ett arbetsutkast (Working Draft) från W3C:s arbetsgrupp
Web Application Security.

## Varför det spelar roll

Attacken som CSP byggdes mot är cross-site scripting, ofta förkortat XSS. Någon
lyckas få in text som de själva har valt i en sida, via ett kommentarsfält, en
sökterm som ekas tillbaka i HTML-koden eller ett kapat beroende, och webbläsaren
kör den som skript med samma befogenheter som webbplatsens egen kod: den kan
läsa sidan, agera som den inloggade användaren och skicka det den hittar vart
som helst. Det första försvaret är att koda utdata korrekt, så kallad escaping,
och det måste vara rätt i varje mall, på varje rad, varje gång. CSP är det andra
försvaret. När ett misstag i kodningen ändå slinker igenom måste det injicerade
skriptet fortfarande ta sig förbi policyn, och en policy som bara kör skript som
bär just det här svarets nonce avvisar det.

Den begränsar också vad ett skript som faktiskt körs kan nå. `connect-src` avgör
vilka värdar skript får tala med, vilket begränsar vart en skimmer, ett skript
som stjäl kortuppgifter, kan skicka det den samlar in. `frame-ancestors` avgör
vilka webbplatser som får visa sidan i en ram, standardförsvaret mot
clickjacking, där en sida läggs över en annan så att ett klick hamnar någonstans
där användaren aldrig tänkte klicka. `form-action` avgör vart formulär får
skickas, och `base-uri` hindrar ett injicerat `base`-element från att i tysthet
styra om varje relativ adress på sidan.

Det lönar sig att vara exakt om vem CSP skyddar. Policyn körs i webbläsaren, så
den skyddar den som läser sidan mot innehåll som en angripare har planterat där.
Den gör ingenting för servern mot samma person, som kan ändra eller ta bort
headern i sin egen webbläsare på några sekunder. En policy är ett skäl att lita
mindre på sidan, aldrig ett skäl att lita mer på förfrågan.

Kostnaden är mest inventering. En policy tvingar ett team att känna till varje
ursprung som dess sidor laddar från, varje inline-skript och varje
händelsehanterare som är skriven som attribut. En ny webbplats kan byggas mot en
strikt policy från första commit för väldigt lite. En äldre webbplats med
inline-hanterare, en tagghanterare och flera widgetar betalar först för
uppstädningen, och den uppstädningen är oftast det verkliga projektet.

## Så ser det ut i praktiken

Den här webbplatsen lever själv under en sådan policy.
[Sidan om hur vi arbetar säkert](/sv/security/)
listar en strikt Content Security Policy, deklarerad i själva sidan, med
`form-action 'none'`, eftersom webbplatsen inte skickar några formulär
någonstans. Samma sida listar ett eget skript på under en kilobyte och inga
anrop till tredje part alls, och det är det som håller en sådan policy kort:
allt som en sida behöver kommer från en enda värddator, webbplatsens egen, så
det finns väldigt lite att tillåta.

En applikation med inloggade användare behöver mer än en kort lista över
tillåtna källor. På en plattform som lagrar yrkes- och organisationsdata
[sätter middlewaren i Next.js en Content-Security-Policy med en nonce per anrop och `strict-dynamic`](/sv/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/),
tillsammans med HSTS och SameSite-kakor. En ny nonce i varje svar betyder att
bara de skriptelement som servern stämplade i just det svaret körs. Med
`strict-dynamic` i policyn får ett skript som nonce-värdet litar på själv ladda
fler skript, så policyn behöver inte namnge varje värddator som ett
JavaScript-paket hämtar sina delar från. Samma sida är tydlig med var
webbläsarens del slutar. Arbetsantagandet där är att klienten är fientlig, och
policyn är därför ett lager av flera: den skyddar användarna mot injicerad kod,
medan behörigheten avgörs någon annanstans: servern tittar på rättigheterna vid
varje enskilt anrop, och spärrarna i frontenden räknas bara som UX.

## Var det går fel

**Policyn går i drift och halva webbplatsen slutar fungera.** En strikt policy
som skickas direkt till skarpt läge blockerar det inline-skript som ingen kom
ihåg och spårningstaggen som någon lade till för två år sedan. Skicka den först
som `Content-Security-Policy-Report-Only`, läs rapporterna tills de lugnar sig,
tillåt eller ta bort varje källa som de nämner och gå först därefter över till
skarpt läge. Report-only-headern måste vara en riktig header: specifikationen
stöder den inte i ett `meta`-element.

**Listan över tillåtna källor litar på en hel värddator.**
`script-src https://cdn.example.com` tillåter varje fil på den värddatorn,
inklusive gamla versioner av bibliotek och ändpunkter som ekar tillbaka
anroparens indata som skript. Specifikationen säger själv att det är en utmaning
att driftsätta en policy som fungerar mot cross-site scripting, och
rekommenderar det som den kallar en Strict CSP: `script-src` byggt av nonces
eller hashar med `'strict-dynamic'`, plus `base-uri` satt till `'self'` eller
`'none'`.

**`'unsafe-inline'` antas tillåta alla inline-skript.** Så snart en nonce eller
en hash finns i samma källista ignorerar webbläsare som förstår dem
`'unsafe-inline'`. Regeln låter en policy behålla `'unsafe-inline'` som reserv
för webbläsare som är för gamla för att känna till nonces, medan dagens
webbläsare tillämpar den strikta listan, och den överraskar ett team som lägger
till en nonce på ett skript och sedan ser sina andra inline-skript blockeras.

**Nonce-värdet slutar vara en hemlighet.** Specifikationen kräver ett nytt värde
varje gång en policy skickas och ber om minst 128 bitar från en kryptografiskt
säker slumpgenerator. En nonce som är hårdkodad i en mall, eller en hel sida som
lagras med sin nonce i en delad cache och serveras till alla, ger en angripare
precis det värde som behövs för att stämpla ett eget skript.

**En policy i ett `meta`-element gör mindre än samma policy i en header.**
Webbläsaren ignorerar `frame-ancestors`, `report-uri` och `sandbox` när de
kommer den vägen, och policyn styr bara det som kommer efter elementet i
dokumentet, så allt ovanför det i `head` laddas okontrollerat. En webbplats som
inte rår över sina svarsheaders får ändå ett verkligt skydd av en policy i
`meta`, placerad så tidigt i `head` som det går, men skydd mot inramning kräver
headern.

**En andra policy stramar åt i stället för att lätta.** Ett svar kan bära flera
policyer, från ett ramverk, en proxy och ett CDN, och en resurs måste klara var
och en av dem. En tillagd policy kan bara begränsa, så en tillåtande header som
läggs till längre ned i kedjan för att rätta en blockerad förfrågan gör
ingenting, och rättelsen måste göras i den policy som blockerade.

## Läs mer

- [Content Security Policy Level 3](https://www.w3.org/TR/CSP3/) — själva
  standarden, med rekommendationen om Strict CSP och ett avsnitt om hur nonces
  blir stulna.
- [HTML Standard: the meta element](https://html.spec.whatwg.org/multipage/semantics.html)
  — pragmat som tillämpar en policy som deklareras i sidan, direktiven som det
  släpper och varför resurser som hämtas före det kan slinka förbi.
- [Reporting API](https://www.w3.org/TR/reporting-1/) — mekanismen för
  ändpunkter bakom `report-to`, för att läsa överträdelser innan policyn skärps.
- [Trusted Types](https://www.w3.org/TR/trusted-types/) — standarden vid sidan
  av CSP som direktivet `require-trusted-types-for` slår på, riktad mot skript
  som injiceras via DOM.

<https://engineer.company/sv/glossary/csp/>
