Hopp til innhold

Subresource Integrity

en hash en nettleser sjekker en fil mot

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:

$ 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 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 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

Ordliste