# Subresource Integrity

## Hva det er

Subresource Integrity er en mekanisme der en side på forhånd oppgir nøyaktig
hvilke byte et skript eller et stilark skal inneholde, og der nettleseren kaster
filen hvis det som kommer fram, er noe annet. Til daglig forkortes det til SRI.
Siden skriver et kryptografisk sammendrag av filen inn i et `integrity`-attributt
på `script`- eller `link`-elementet som laster den. Når svaret kommer, kjører
nettleseren den samme hashfunksjonen over bytene den fikk, og sammenligner
resultatet med verdien på elementet. Er de like, kjører skriptet eller virker
stilarket på siden som vanlig. Er de ulike, behandler nettleseren svaret som en
nettverksfeil: skriptet blir aldri utført, og stilarket blir aldri brukt.

Verdien består av navnet på en hashfunksjon, en bindestrek og sammendraget i
base64. Én kommando over den ferdige filen lager den, og to kjøringer viser hvor
lite som skal til for å endre svaret:

```text
$ printf "alert('Hello, world.');" > hello.js
$ openssl dgst -sha384 -binary hello.js | openssl base64 -A
H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
$ echo >> hello.js
$ openssl dgst -sha384 -binary hello.js | openssl base64 -A
qu8P7hCLFcBpas8BOnGmaANCkfXJIpFttDEaxOj0Pq9H6Q8NYjsMb+PVqwuJygVe
```

Med `sha384-` foran er den første linjen med utdata verdien attributtet skal ha
for det enlinjes skriptet. Ett linjeskift lagt til på slutten gir et sammendrag
som ikke har noe til felles med det første, og en nettleser som holder det
første, ville avvise den andre filen.

Spesifikasjonen kjenner tre hashfunksjoner, SHA-256, SHA-384 og SHA-512, alle
fra SHA-2-familien, og omtaler SHA-384 som et godt utgangspunkt da teksten ble
skrevet. Et attributt kan liste flere sammendrag atskilt med mellomrom.
Nettleseren velger den sterkeste funksjonen blant dem og godtar filen når den
stemmer med ett av sammendragene laget med den funksjonen. Slik kan en side gå
over til en sterkere algoritme, eller godta to utgivelser av et bibliotek mens
de byttes, uten et tidsrom der siden bare bærer feil verdier.

Attributtet finnes på `script` og `link`, og den samme verdien kan følge med i
en `Link`-header i svaret som forhåndslaster en fil. Gjeldende tekst er andre
utgave, et W3C-arbeidsutkast fra Web Application Security Working Group. Den
første utgaven ble en W3C-anbefaling i 2016.

## Hvorfor det er viktig

En side som laster et bibliotek fra et CDN, eller fra en hvilken som helst vert
eierne ikke selv drifter, gir den verten makt til å kjøre kode på siden. HTTPS
beskytter filen på veien over nettet, men sier ingenting om hva verten valgte å
sende i utgangspunktet. Blir lagringen hos CDN-et brutt opp, blir en konto som
publiserer dit, overtatt, eller blir filen bak en kjent adresse byttet ut i det
stille, kjører hver side som tar den med, den nye koden med hele sidens
myndighet. Sidens egen kode har ingen måte å merke forskjellen på.

SRI flytter den avgjørelsen tilbake til siden. Sammendraget lages av eieren av
nettstedet over en fil de har lest eller bygd selv, og det reiser inne i siden,
fra nettstedets egen server. En vert som leverer noe annet, får filen sin avvist
i stedet for kjørt. Siden mister en funksjon til noen ser på den, en synlig feil
med en åpenbar årsak, og slipper å kjøre andres kode uten at noen merker det.

Sammendraget låser også en versjon. En adresse som `/lib/latest.js` kan når som
helst begynne å levere en ny utgivelse under en side, og det kan ikke
sammendraget følge etter. En oppgradering eieren aldri valgte, blir en avvisning
på ett bestemt element, meldt gjennom en feilhendelse.

Det lønner seg å være presis om hva SRI lar være. Mekanismen sjekker en fil mot
et sammendrag og vurderer aldri om filen er trygg. Et sammendrag av et bibliotek
som allerede inneholder en fiendtlig linje, beskytter den fiendtlige linjen
trofast. Skript skrevet rett inn i siden faller utenfor, og der er det en
Content Security Policy som gjør jobben. Og mekanismen
stoler på siden som bærer sammendraget, så selve siden må fortsatt komme fram
uendret.

## Slik ser det ut i praksis

Dette nettstedet bruker det på sitt eget stilark.
[Siden om hvordan vi arbeider sikkert](/nb/security/) lister Subresource
Integrity på stilarket: pakken får et fingeravtrykk og en hash når nettstedet
bygges, slik at nettleseren til leseren kan bekrefte at den kom fram uendret.
Den samme listen viser hvorfor ordningen holder seg liten. Det finnes ett
førstepartsskript på under en kilobyte, ingen forespørsler går til tredjeparter,
og en leser som teller vertene i nettverkspanelet i nettleseren, finner én,
nettstedets egen.

[Kolofonen](/nb/credits/) beskriver den samme filen sett fra bygget, som én
CSS-pakke satt sammen og merket med et fingeravtrykk ved bygging og levert med
en SRI-hash. Fingeravtrykket legger en hash av innholdet inn i filnavnet, så et
endret stilark får en ny adresse, og en nettleser tar aldri feil av en gammel
kopi i hurtigbufferen og den gjeldende. Integritetsverdien lar nettleseren
sjekke bytene bak den adressen. Bygget lager begge deler fra de samme bytene i
det samme trinnet, så hver utgivelse leverer stilarket og sammendraget sammen,
og den vanligste feilen beskrevet nedenfor, en fil som endres etter at den ble
hashet, har svært lite rom til å skje.

## Hvor det går galt

**Et ledd mellom bygget og nettleseren som skriver om filen.** Et CDN som
minifiserer skript, en proxy som komprimerer på nytt eller sprøyter inn noe i
svarene, eller et steg i produksjonssettingen som kjører etter at sammendraget
ble tatt, endrer alle bytene, og nettleseren avviser resultatet selv om ingen
har angrepet noe. Spesifikasjonen legger ansvaret på disse mellomleddene: de må
holde sammendraget i takt med det de leverer, eller levere originalen urørt, og
opphavet bør sende `Cache-Control: no-transform` for å be dem la filen være. Den
pålitelige rekkefølgen er å ta sammendraget sist, over nøyaktig de bytene som
skal leveres.

**En fil fra et annet opphav som kommer uten CORS.** Spesifikasjonen krever at
en integritetssjekk av en fil fra et annet opphav bruker CORS, og kaller et
forsøk uten det en logisk feil. Elementet trenger derfor
`crossorigin="anonymous"`, og verten må svare med en header som deler filen.
Mangler én av dem, blokkerer nettleseren filen heller enn å laste den usjekket.
Regelen beskytter andre nettsteder. Fantes den ikke, kunne en angriper laste et
privat svar med et gjettet sammendrag og lære noe av utfallet, f.eks. om leseren
er logget inn der.

**Et sammendrag som kommer over ukryptert HTTP.** SRI beskytter en side mot en
kompromittert vert for filer, aldri mot noen på nettverksveien. På en side
levert uten HTTPS kan den som kan skrive om filen underveis, like godt skrive om
eller slette sammendraget i siden, så spesifikasjonen anbefaler å levere
integritetsdata bare til en sikker kontekst.

**En hashfunksjon nettleseren hopper over.** Spesifikasjonen kjenner bare
SHA-256, SHA-384 og SHA-512 og anbefaler at nettlesere avviser kjent svake
funksjoner som MD5 og SHA-1. Overraskelsen er hva som skjer med en verdi utenfor
den listen: nettleseren overser den, og et attributt som bare består av oversette
verdier, regnes som om det ikke bar noen data i det hele tatt, så filen lastes
usjekket. Et byggverktøy som kan lage fingeravtrykk med MD5, slik Hugo kan, gjør
det lett å sende dette ut ved et uhell.

**En avvist fil som tar siden med seg i fallet.** Når sjekken feiler, sender
nettleseren en feilhendelse på elementet, og skriptet eller stilarket er rett og
slett borte. For et bibliotek siden ikke klarer seg uten, foreslår
spesifikasjonen å fange hendelsen og laste en reservekopi fra en kilde du stoler
på, om enn tregere, f.eks. nettstedets egen server. Mangler en slik reserve,
virker beskyttelsen som tenkt, og leseren får likevel en ødelagt side.

**En sjekk som bare dekker elementene med et sammendrag.** Et
integritetsattributt på ett skript sier ingenting om det neste noen legger til
uten, og en gjennomgang av skriptene som har ett, vil aldri avsløre det som
mangler. Utkastet legger til en header i svaret som dekker dette fra
serversiden. `Integrity-Policy` med `blocked-destinations=(script)` blokkerer
hvert eksterne skript som kommer uten integritetsdata, og
`Integrity-Policy-Report-Only` lister dem først, så de kan rettes før noe blir
blokkert.

## Les mer

- [Subresource Integrity](https://www.w3.org/TR/SRI/)
  — det gjeldende utkastet, med algoritmen for verifisering,
  `Integrity-Policy`-headerne og merknadene om proxyer, ukryptert HTTP og
  lekkasjer på tvers av opphav.
- [Subresource Integrity, W3C Recommendation 2016](https://www.w3.org/TR/2016/REC-SRI-20160623/)
  — første utgave, den stabile anbefalingen utkastet vokste ut av.
- [Fetch Standard](https://fetch.spec.whatwg.org/)
  — der integritetsdataene i en forespørsel sjekkes mot innholdet i svaret, og
  CORS-protokollen en sjekk på tvers av opphav er avhengig av.
- [Hugo: resources.Fingerprint](https://gohugo.io/functions/resources/fingerprint/)
  — hvordan en statisk nettstedsgenerator lager et fingeravtrykk av en fil ved
  bygging og gir tilbake den tilhørende integritetsverdien.
- [FIPS 180-4, Secure Hash Standard](https://csrc.nist.gov/pubs/fips/180-4/upd1/final)
  — den føderale amerikanske standarden som definerer SHA-256, SHA-384 og
  SHA-512.

<https://engineer.company/nb/glossary/sri/>
