Forsyningskjedesikkerhet
Når vi bygger software har vi avhengigheter til en hel haug med ulike tredjepartspakker fra økosystem som npmjs, nuget, PyPi og liknende. I CI/CD-pipelines har vi actions og kode som gjennomfører testing, bygging, deployment og liknende. Alt dette er kode og komponenter som kommer fra tredjepart, der vår grad av sikkerhet er prisgitt hvordan disse aktørene jobber. En svakhet i en avhengighet kan resultere i at vårt prosjekt lekker data, at kode manipuleres eller brukes til ondsinnede handlinger.
Sikkerhetsrisiko
Når vi tar i bruk tredjepartskomponenter er det viktig å ha et forhold til risiko. Nyttige kontrollspørsmål er
- Hvem står bak
- Trenger vi egentlig denne komponenten?
- Vedlikeholdes den aktivt?
- Har utgiver en historikk som tilsier at sikkerhet tas seriøst?
Det finnes ingen fasitsvar som sier når risiko er for stor, men du kan redusere den med noen forholdsvis enkle grep. Her er det imidlertid viktig å skille mellom ondsinnede og sårbare komponenter!
Ondsinnede komponenter
De ondsinnede komponentene lages for å utføre uønskede handlinger som datalekkasjer, kryptomining, stjeling av hemmeligheter og mye annet. De siste få årene har vi sett helt nye typer ondsinnede pakker som går målrettet etter utviklingsprosjekter og utviklere, som GlassWorm, Shai-Hulud og andre. Felles for disse er at de utgir seg for å være legitime, enten ved å benytte seg av pakkenavn som likner på reelle ufarlige komponenter, alternativt ved at de som en del av angrepet henter ut brukernavn, passord, accesstokens og annet til utviklere som også eier legitime pakker, slik at de kan infisere disse.
Kampanjer med ondsinnede komponenter går ofte i bølger, der trusselaktørene forsøker å utnytte trender. For noen år siden var kryptovaluta det store, og en kunne observere mye malware som utga seg for å være kjente eller nyttige biblioteker relatert til dette. De siste par årene har en sett det samme med KI, der en går målrettet etter utviklere og brukere som er nysgjerrige og ute etter å bruke “det siste nye”.
Sårbare komponenter
Det er veldig sjelden vi klarer å lage perfekt software helt uten svakheter. I mange tilfeller har vi noen kjente sårbarheter som regnes som så harmløse at vi kan leve med dem, men i forholdsvis mange tilfeller oppdages det alvorlige sårbarheter etter release.
Utfordringen som har dukket opp de siste årene med bruk av KI er at det å oppdage samt utnytte slike sårbarheter kan gå svært raskt, og vi er nødt til å følge med. I mange tilfeller der det oppdages en sårbarhet vil det typisk også opprettes en CVE-rapport (Common Vulnerabilities and Exposures), som sier noe om hva svakheten går ut på og ofte hvordan den kan mitigeres.
I noen tilfeller kan vi løse problemet ved å oppgradere pakkene til siste versjon, mens andre har mer grunnleggende utfordringer som krever mer innsats. Det hender også at noen CVE’er lages på svakheter som teknisk sett er en sårbarhet, men der den er ‘by-design’. Et eksempel på dette er Python-pakken Pandas som blant annet har sårbarheten CVE-2020-13091. Denne lar brukeren deserialisere filer uten sjekk av hvor disse kommer fra - dette har da blitt registrert som en sårbarhet da den kan utnyttes dersom andre tiltak ikke er på plass.
Lisensmodell
Det finnes mange ulike lisensmodeller; noen er helt frie og får ingen konsekvenser for brukerne, mens andre som AGPL og GPL stiller klare krav til alle som konsumerer kode under denne lisensen, også inkludert det øvrige systemet som benytter seg av den. De aller fleste økosystemer tillater også bruk av proprietære lisenser, som kan begrense hva du kan bruke en pakke til. Noen har spesifikke krav i lisensen, andre er gratis for personlig bruk, men krever at du kjøper en lisens dersom den skal brukes kommersielt.
Hvordan sikrer vi oss?
For å beskytte systemet mot disse truslene er det flere effektive tiltak vi kan gjøre. Mange av disse er allerede dekket andre steder, men det er likevel noen som er unike for eksterne pakker.
Trusselmodell og kompleksitet
I mange tilfeller har vi avhengigheter til mange pakker som ikke brukes av oss direkte, såkalte transitive avhengigheter. Hver enkelt pakke kjører i samme kontekst som vår egen kode, og kan bruke de samme ressursene og tilgangene den har. Hver avhengighet representerer derfor en økning i kompleksitet og angrepsflate, og øker sjansen for at noe skjærer seg på et senere tidspunkt.
braces
fill-range
to-regex-range
is-number
Et viktig spørsmål alle må stille seg er “trenger vi denne pakken?” Hva er kosten ved å lage funksjonaliteten selv sammenliknet med risikoen og kompleksiteten assosiert med å legge den til?
Overvåkning av avhengigheter
Et viktig hjelpemiddel er analyseverktøy som hjelper oss å ha kontroll på sårbarheter og risiko i avhengighetene våre. Denne typen analyse kalles Software Composition Analysis (SCA), og gir oversikt over både direkte og transitive avhengigheter samt risikoen knyttet til dem. Det finnes mange aktører på markedet, alt i fra helt enkle som Githubs Advanced Security med Dependabot, til mer avanserte som Snyk og Sonatype. I mange tilfeller er det datagrunnlaget for løsningen som utgjør den store forskjellen, men det finnes også en del nyttige funksjoner en bør vurdere:
- Policystyring - Sonatype tagger alle pakker med metadata, slik at du kan definere policyer som sier noe om hva som kan brukes eller ei.
- Automatisk utbedring - Verktøy som dependabot (Github) oppgraderer automatisk pakker når sårbarheter oppdages og oppdateringer er tilgjengelige.
- Integrasjoner og varsling - Mange verktøy som eksempelvis Snyk SCA kan integreres i IDE og i CICD.
- Risikobilde - Mange løsninger gir deg en totaloversikt der du kan se det totale risikobildet for enkeltapplikasjoner eller større deler av porteføljen
AI-avhengigheter er også en del av forsyningskjeden
For systemer som bruker KI er ikke avhengigheter bare biblioteker fra npm, nuget eller PyPI. Modeller, tokenizers, embeddings, evalueringsdatasett og containere for inferens må behandles som tredjepartsavhengigheter med samme krav til kontroll.
Det betyr blant annet at teamet bør:
- bruke godkjente kilder og unngå nedlasting av artefakter direkte fra ukjente speil
- låse versjoner og referere til immutable identifikatorer (tag alene er ikke nok)
- dokumentere hvilke AI-artefakter som faktisk inngår i en release
- vurdere lisens og bruksvilkår også for modeller og datasett, ikke bare kode
Modenhet
Denne kan være vanskelig å si noe konkret om, men hvor aktivt er miljøet rundt en pakke? Vedlikeholdes den av enkeltpersoner, grupper med utviklere eller har den økonomisk eller annen støtte fra et selskap?
Hvor sannsynlig er det at pakken fortsatt kommer til å være vedlikeholdt om eksempelvis 5 år? Hvordan er historikken i forhold til sårbarheter og kvalitet; finnes det et aktivt miljø som rapporterer svakheter som deretter utbedres, eller henger innmeldte saker i limbo over lengre tid? Verktøy som libraries.io og Security Scorecard kan være nyttige for å finne ut mer.
Pinning av versjoner
En av angrepsvektorene er når ondsinnede aktører overtar populære pakker, og publiserer sin egen versjon med ondsinnet innhold. Dersom vi har bygg eller deployprosesser som henter siste versjon av avhengighetene hver gang, vil disse automatisk hente den infiserte pakken. Et tiltak her kan være å låse pakkeversjonene vi bruker, eksempelvis i package-lock.json eller liknende.
Et beslektet tiltak er å innføre en form for cooldown eller alderskrav på nye versjoner, slik at vi ikke tar i bruk oppdateringer før de er et visst antall dager gamle. Hensikten er å redusere risikoen for å plukke opp fersk malware eller kompromitterte pakker før økosystemet rekker å oppdage problemet og fjerne eller flagge versjonen. Dette kan være spesielt nyttig for automatiserte oppdateringsløp, men bør brukes risikobasert slik at kritiske sikkerhetsoppdateringer fortsatt kan tas inn raskt gjennom en kontrollert unntaksprosess.
Provenance og policy-gates i CI/CD
I tillegg til pinning bør byggløpet verifisere opprinnelse og integritet for avhengigheter før de tas i bruk. Teamet bør etablere policy-gates i CI/CD som kan stoppe merge eller deploy ved kritiske avvik, eksempelvis ved alvorlige sårbarheter, ulovlige lisenser eller avhengigheter fra ikke-godkjente kilder.