Det er ikke mulig å gi en oppskrift på hvordan man skriver sikker programkode i noen få, enkle og kortfattelige artikler. Det betyr derimot ikke at det er en uoverkommelig oppgave forbeholdt sikkerhetseksperter! Alle som utvikler programvare i Bouvet skal være kjent med OWASP Top 10, som er et godt utgangspunkt for å bli kjent med hvilke utfordinger man står ovenfor som utvikler.
Artikklene du finner under temaet Utvikle på denne siden vil fokusere på det som foregår på en utviklers arbeidsmaskin, som ikke er konkret kode. De vil ikke gå i dybden på konkrete angreps metoder eller hvordan beskytte mot disse. Du vil også finne råd om hvordan et team bør arbeide for å være i stand til å forebygge, identifisere, og fikse sårbar kode.
1 - Utviklingsmiljø, verktøy og byggmiljø
Miljøene og verktøyene vi jobber med er essensielle for prosjektet. Teamet bør standardisere verktøybruk, dokumentere oppsett og redusere risiko i utviklings- og byggkjeden.
Utviklingsmiljøet og byggmiljøet er noe av det viktigste vi har i et utviklingsprosjekt. Disse miljøene er både en produktivitetsfaktor og en kritisk del av angrepsflaten. Noen team utvikler og bygger lokalt på egen laptop, mens andre bruker dedikerte utviklings- og byggmiljø basert på skytjenester eller on-prem utviklingsservere. Uavhengig av løsning er det noen grunnprinsipper som bør være på plass: tydelig eierskap, dokumenterte valg, standardiserte oppsett og jevnlig oppfølging.
øvrige tjenester som teamet drifter eller konsumerer, for eksempel meldingstjenester, filoverføring og KI-verktøy
Disse verktøyene har stor betydning for sikkerhet og kvalitet i leveransen. Derfor bør teamet avklare hvilke verktøy som er tillatt, hvordan de settes opp, og hvordan endringer eller oppdateringer håndteres der dette er relevant.
Utvidelser og extensions
Mange verktøy tillater bruk av ulike utvidelser for å tilby funksjonalitet fra tredjepart som ikke er bygd inn i verktøyet fra leverandøren. Dette gjør det mulig å bruke standardverktøy som VS Code, som tilpasses til hvert enkelt prosjekt med de utvidelsene som er relevante for teknologivalg og arbeidsprosess.
Utvidelser er imidlertid en stor angrepsvektor, så det er viktig å ha noen grunnprinsipper som hjelper teamet å vurdere kvaliteten dem. Leverandører som KOI tilbyr løsninger for å hjelpe med dette, men i mangel av verktøy er det noen grunnprinsipper som kan hjelpe:
Ikka ta utvidelser ukritisk i bruk. Vurder historikk, opphav og oppdateringsfrekvens.
Har utvidelsen historikk i form av tidligere sårbarheter eller liknende; dersom ja, hvordan ble de håndtert?
Følg med på utvidelsene du har, sett deg inn i endringer før du oppdaterer. Vurder også å avvente oppdatering til noen dager etter at den er tilgjengelig.
Som med alt annet på internett; stjerner, ratings og omtaler kan ikke stoles på og bør ikke være grunnlag for å avgjøre hvorvidt noe skal tas i bruk eller ei.
KI i utviklingsmiljøet
Generative AI-verktøy kan gi høyere utviklingstakt, men innfører også nye risikoer. Bruk av KI må avklares med kunden før verktøy tas i bruk.
Sentrale avklaringer er:
hvilke KI-tjenester som er godkjent
hvilke data som kan brukes i prompt og som underlag
hvordan leverandøren lagrer og gjenbruker data
hvordan bruk av KI dokumenteres i teamet
En enkel tommelfingerregel er at kode, arkitektur, logger og konfigurasjon behandles som sensitiv informasjon inntil annet er avklart.
Versjonskontroll
Versjonskontroll gir sporbarhet og kontroll over endringer, men sikkerhetsgevinsten avhenger av hvordan arbeidsflyten brukes i praksis. Repositories og branchingstrategi bør konfigureres etter prosjektets behov.
Flere kontroller krever tilleggsverktøy og lisenser. Vær særlig oppmerksom på verktøy som sender kode til eksterne tjenester for analyse. Det er også viktig å være klar over at eksempelvis actions som brukes som en del av CI/CD er en angrepsvektor, og at de må vurderes og behandles som alle andre komponenter i forsyningskjeden.
Forsyningskjedesikkerhet i praksis
Moderne programvare bygges av mange avhengigheter. Derfor må teamet ha kontroll på hele forsyningskjeden, ikke bare egen kode. Husk på at forsyningskjeden dekker alle avhengigheter teamet har, ikke bare pakker og biblioteker.
Teamet bør sikre at dere har kontroll på avhengigheter og risiko ved å bruke disse. Vanlige eksempler på komponenter en bør ha oversikt over er:
IDE og andre koderedigeringsverktøy
KI-verktøy
Utvidelser/plugins
Støtteverktøy som Figma, databasemodelleringsverktøy eller liknende
Skykomponenter
Versjonskontroll
CI/CD - også inkludert actions som kjøres
Rammeverk, pakker og bibliotek
Det er ikke gitt at teamet styrer alt, men en bør likevel ha et forhold til hvordan livssyklusen på disse håndteres og hvordan endringsprosessene fungerer i praksis.
Utviklingsmiljø og byggmiljø
Et av de store risikoelementene ved all utvikling er dersom:
uvedkommende kan nå en maskin som brukes til utvikling, bygging eller produksjon
maskinen kan nå internett uten særlige begrensninger
slike maskiner mangler monitorering
Alle utviklere har avhengigheter til biblioteker og pakker fra open source-økosystemer. Noen av disse kan kompromitteres eller forfalskes, og dermed introdusere bakdører eller eksfiltrering av data.
Viktige tiltak for å redusere risiko er å:
stenge for all innkommende nettverkstrafikk
stenge for all utgående nettverkstrafikk
kun åpne opp for de tilgangene som absolutt trengs
unngå bruk av generelle maskiner som brukes til surfing på nett, kontoraktiviteter og liknende til utvikling
Det er ikke alltid mulig å forsvare dedikerte maskiner for utvikling ut fra kost/nytte. Dette bør likevel vurderes bevisst, slik at teamet kjenner hvordan valget påvirker risikobildet.
Minimum som bør dokumenteres
Følgende bør minimum være dokumentert og vedlikeholdt:
godkjente verktøy og versjoner
krav til oppsett av utviklingsmaskiner og byggmiljø
Versjonskontroll er et essensielt verktøy i alle utviklingsprosjekt, men hvordan bruker du det effektivt og hva bør du tenke på?
Git er idag standard i de fleste prosjekter som kjøres i Bouvet, men skulle du havne i et prosjekt som bruker noe annet vil mange av prinsippene likevel være overførbare. Git i seg selv er selve versjonskontrollverktøyet som håndterer historikk og versjonering, mens Github håndterer alt rundt som CI/CD, sikkerhetstesting og liknende. Azure DevOps har mange de samme funksjonene som beskrives under; selv om Github er brukt som eksempel bør du anta at det samme gjelder for Azure DevOps.
Det første du bør gjøre i et nytt eller eksisterende repository, er å sjekke at det finnes en .gitignore-fil. Denne brukes for å ekskludere filer fra git, slik at de kan leve i mappene dine lokalt uten å bli sjekket inn til git. Det finnes ferdige templates for de fleste programmeringsspråk, som sikrer at byggfiler, .env-filer og annet som kan inneholde sensitiv informasjon ikke sjekkes inn i git.
Ikke baser deg på at du skal “huske” å ikke inkludere filer når du committer; det er fort gjort å bomme når du skal fikse noe i forbifarten. .gitignore sjekkes inn som med andre filer, slik at andre i teamet også kan få glede av den. Husk bare på at den kun gjelder nye filer; dersom du også vil ekskludere filer som allerede ligger i repoet må de først slettes fra githistorikken.
Hemmeligheter og historikk
Mange tester lokalt på egen maskin mens de utvikler, og har gjerne nøkler og liknende hardkodet mens de tester. Det skjer forholdsvis ofte at man glemmer å slette slike hemmeligheter!, og at de sjekkes inn som med annen kode. Dersom dette skjer, må hemmeligheten ugyldiggjøres. Nøkler, passord, sertifikater og liknende må roteres slik at det som havnet i git ikke lenger er gyldig.
Å overskrive i git er ikke nok; historikken vil fremdeles være tilgjengelig for alle med tilgang. Alle som har klonet repoet vil også ha en kopi av historikken; selv om det finnes en teknisk mulighet for å omskrive historikken vil dette i mange tilfeller kunne være vanskelig eller umulig.
Håndtering av hemmeligheter
Bruk passordhvelv for å håndtere hemmeligheter: Du refererer til hemmeligheten, men kan skille miljøer fra hverandre ved å peke på ulike hvelv!
Secret scanning
Vurder å sette opp workflows som scanner repoet for hemmeligheter, eksempelvis ved bruk av [Trufflehog]
(https://github.com/marketplace/actions/trufflehog-oss) eller liknende slik at merge blokkeres ved funn av hemmeligheter. Det vil ikke kunne være en perfekt løsning, men vil varsle ved funn og forhindre at hemmeligheter havner i main.
Github støtter også bruk av ulike actions, som kan utføre oppgaver på kode som sjekkes inn, som CI/CD, sikkerhetstesting og mye annet.
Tilgangsstyring
Tilgangsstyring er første punkt på agendaen i et nytt prosjekt. Hvem skal ha tilgang til repoet - enkeltbrukere, organisasjonen, eller skal det være public? Vær obs på at vi kun får lage private repos som utgangspunkt, skal det åpnes opp må dette skje via en BSD-sak.
Kodesignering
Git i selg selv har ingen form for tilgangsstyring; alle kan konfigurere git-klienten sin og kan kalle seg Pelle Pellesen, med eposten [email protected]@, og det dette som normalt vil vises i historikken. Avhengig av prosjektet og eventuelle kundekrav bør en vurdere bruk av signed commits for å sikre at alle commits signeres kryptografisk.
Bildet over viser eksempelvis hvordan en commit til akkurat denne artikkelen vises når den er signert.
Git hooks
Git hooks er skript som typisk kjøres clientside og trigges av ulike handlinger slik at en kan kjøre linting, kodescanning og annet for å sikre kvaliteten i det som utvikles. Selv om det finnes både clientside og serverside hooks, er det viktig å være klar over at Github ikke støtter kjøring av serverside hooks.
Hooks lever i utgangspunktet under .git; da denne ikke er versjonskontrollert bør skript legges inn under andre mapper slik at en kan dele dem på tvers i teamet. Husk at hooks må settes opp av hver enkelt utvikler, så ikke legg kritiske sjekker utelukkende i disse!
Workflows
Workflows kjøres på Github, og kan trigges av ulike hendelser som pushing av kode, i forbindelse med pull requests, tags og annet. En workflow kan bestå av en rekke ulike actions som kjøres mot kodebasen. Workflowene brukes ofte for å validere, teste, bygge eller deploye; i forkant av en pull request kan en eksempelvis kjøre en rekke tester for å se at endringene ikke brekker eksisterende funksjonalitet, før det kjøres en ny workflow etter merge til main som bygger og deployer koden på ønsket sted.
Vær obs på at workflows spinner opp en VM eller en container på baksiden der de ulike actionene kjøres, og at mange av disse i realiteten har avhengigheter til tredjepart. Ikke kjør actions ukritisk, men ta en vurdering på hvilken risiko/nytte de gir i likhet med alle andre avhengigheter.
Branchingstrategi
Git støtter ulike former for branching, avhengig av hvor kompleks arbeidsflyt en trenger. Uavhengig av hva en går for, er det viktig å ha et forhold til hvordan arbeidsflyten vil være dersom det plutselig dukker opp svakheter eller sårbarheter som må fikses, uavhengig av hva en ellers jobber med.
En typisk tilnærming er å operere med en produksjonsbranch, ofte main eller master. Denne bør være beskyttet slik at alle endringer skjer i egne feature-branches som så merges inn via pull-request med dertilhørende review fra andre i teamet. Produksjonsbranchen blir så grunnlaget for alle deployments videre.
Det finnes andre og mer komplekse tilnærminger også, eksempelvis med separate branches samt tagging av versjoner. Denne er spesielt nyttig dersom en vedlikeholder flere ulike versjoner i ulike miljø, trenger mulighet for hotfixer eller liknende:
I dette eksempelet jobber alle utviklere i egne feature branches mot develop-branchen, som beskyttes mot direkte endringer. Denne deployes til dev-miljøet for å verifisere at alt fungerer som det skal.
Når teamet er fornøyed med tilstanden på develop, merges denne til test via en egen pipeline som håndterer tagging av versjonsnummer automatisk. Denne pipelinen kan kreve godkjenning for å kjøre, slik at det trengs en person for å starte den, og en annen for å godkjenne.
Test-branchen deployes til testmiljøet, og når kunden er fornøyd med det som er levert merges den til prod-branchen på samme måte som til test. For både test og prod bruker vi versjonsnummeret som en del av branchnavnet, slik at vi kan ha branchen Test/v1 og Test/v2, som korresponderer med Prod/v1 og Prod/v2.
Dersom det er behov for hotfixing mot prod kan dette eksempelvis gjøres mot den aktuelle prodbranchen slik at en får korrigert kritiske feil raskt, for så å ta hotfixen tilbake til dev.
Datavalidering reduserer både sikkerhetsrisiko og kvalitetsfeil. Ikke stol blindt på data, verken fra brukere, integrasjoner eller AI-pipelines.
Datavalidering er grunnleggende i alle utviklingsprosjekter. Formålet er å sikre at data har forventet struktur, innhold og kvalitet før de brukes videre i systemet.
Feil eller ondsinnet data kan føre til:
sikkerhetssårbarheter, som injeksjon og XSS
funksjonelle feil og ustabil drift
feil beslutningsgrunnlag i rapportering og analyse
redusert kvalitet i AI-modeller og evaluering
OWASP Top 10 har over tid vist at mangelfull validering av input er en gjentakende årsak til alvorlige sårbarheter. Hovedregelen er enkel: data skal valideres ved tillitsgrensen, uansett kilde.
Grunnprinsipper
Datavalidering bør bygges inn i arkitektur og kode, ikke legges til som et etterslep.
Valider tidlig: Stopp ugyldige data så nær inngangspunktet som mulig.
Valider eksplisitt: Definer hva som er gyldig, i stedet for å prøve å blokkere alt som er farlig.
Valider i flere lag: Kombiner klientvalidering, servervalidering og validering i meldings-/integrasjonslag.
Fail closed: Dersom data ikke kan verifiseres, avvis eller sett dem i karantene.
Logg avvik: Logg valideringsfeil med nok kontekst til feilsøking, uten å lekke sensitive data.
Anbefalte kontroller i alle prosjekter
Minimumskontroller som bør være på plass i vanlige utviklingsprosjekter:
Skjema og kontrakter: Bruk tydelige skjema (for eksempel JSON Schema, OpenAPI eller tilsvarende) mellom tjenester for å oppdage kontraktsbrudd tidlig.
Type- og formatvalidering: Valider datatype, lengde, tillatte tegn, intervaller, datoformat og encoding.
Semantisk validering: Sjekk regler som ikke fanges av type alene, som gyldige statusoverganger eller avhengigheter mellom felt.
Kontekstavhengig output-escaping: Escape data korrekt før visning i HTML, URL, JavaScript eller SQL-kontekst.
Filvalidering: Verifiser MIME-type, filsignatur, filstørrelse og tillatte filtyper. Skann opplastede filer for malware.
Isolert behandling av risikodata: Vurder sandbox for parsing og behandling av potensielt farlige filer.
Det er mye å tenke på dersom en skal bygge en sikker løsning, og et viktig utgangspunkt er OWASP Top 10.
Det finnes mange ulike typer sårbarheter og svakheter vi må forholde oss til når vi utvikler nye applikasjoner. Organisasjonen Open Worldwide Application Security Project (OWASP) publiserer en prioritert liste over vanlige applikasjonssårbarheter som brukes av mange team som et praktisk utgangspunkt.
OWASP Top 10 er ikke en komplett sikkerhetsstandard, men en nyttig prioritering av hva som typisk går galt i virkelige prosjekter.
Gjeldende punkter i OWASP Top 10
Per i dag er siste publiserte versjon OWASP Top 10:2025:
A01:2025 - Broken Access Control
A02:2025 - Security Misconfiguration
A03:2025 - Software Supply Chain Failures
A04:2025 - Cryptographic Failures
A05:2025 - Injection
A06:2025 - Insecure Design
A07:2025 - Authentication Failures
A08:2025 - Software or Data Integrity Failures
A09:2025 - Security Logging and Alerting Failures
A10:2025 - Mishandling of Exceptional Conditions
Fra Top 10 til praksis i teamet
Dersom teamet ikke har noen prosesser rundt sikker utvikling, er dette et godt sted å starte. For å få effekt i praksis må punktene omsettes til konkrete kontroller i leveranseløpet.
definere sikkerhetskrav tidlig og knytte dem til arkitektur og brukerhistorier
gjennomføre kodegjennomgang og tester som inkluderer sikkerhetsrelevante scenarioer
bruke automatiserte kontroller i CI/CD for avhengigheter, konfigurasjon og hemmeligheter
sikre sporbarhet på endringer, bygg og deploy
oppdatere trusselmodell og risikovurdering ved større endringer
For team med større modenhet innenfor applikasjonssikkerhet er OWASP ASVS et naturlig neste steg. ASVS går mer i dybden enn Top 10 og kan brukes som verifikasjonsgrunnlag i ulike modenhetsnivå.
Hva med AI?
OWASP Top 10 for webapplikasjoner dekker fortsatt mange grunnleggende problemer, også i løsninger som bruker KI. Samtidig introduserer KI egne trusler som ikke dekkes fullt ut av denne listen alene.
For prosjekter med KI-komponenter bør teamet i tillegg bruke:
OWASP publiserer mye annet i tillegg, både andre Top 10-lister og det de kaller “cheat sheets”, som gir mer detaljert informasjon om spesifikke sikkerhetstema.
Alle som lager programvare bruker tredjepartspakker. Alle tredjepartspakker representerer kode skrevet av andre, og utgjør en risiko for leveransen dersom vi ikke har kontroll over hva vi bruker og oversikt over svakheter og risiko assosiert med disse.
Når vi bygger software har vi avhengigheter til en hel haug med ulike tredjepartspakker, fra økosystem som npmjs, nuget, PyPi eller andre. Dette er kode “skrevet av andre”, der vi er avhengige av at disse produserer pakker uten større svakheter og uten onde hensikter. Kilder som blant annet Gartner, Sonatype og Snyk har anslått at så mye som 90% av koden i et typisk utviklingsprosjekt kan bestå av slike tredjepartspakker, så risikoen er betydelig dersom vi ikke har kontroll.
Et viktig hjelpemiddel er å gjennomføre en såkalt Source Composition Analysis - SCA for å få oversikt over pakkene vi bruker, både direkte og indirekte (transiente) avhengigheter, samt risikoen assosiert med disse.
Sikkerhetsrisiko
Det finnes flere sikkerhetsrisikoer knyttet til tredjepartspakker, men dessverre er økosystemene for slike pakker lite proaktive på sikkerhetsfronten. Infiserte pakker som identifiseres blir fjernet, men for alle som bruker automatikk for å holde avhengigheter oppdatert til siste versjon kan dette ofte være for sent.
Sårbarheter
De kan inneholde kjente sårbarheter (CVE) som kan la seg utnytte. Noen av disse kan mitigeres ved å oppgradere pakkene til siste versjon, andre har mer grunnleggende utfordringer som kan mitigeres på annet vis. 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 det vil kunne være mulig utnytte dette om andre tiltak ikke er på plass.
Ondsinnet kode
Pakkene vi laster ned og bruker kjøres i samme kontekst som vår kode og kan benytte de samme ressursene og tilgangene den har. Innholdet i pakkene vi konsumerer er helt utenfor vår kontroll, og dersom en av dem inneholder ondsinnet programvare (malware) kan konsekvensene bli store.
De siste årene har det også dukket opp eksempler på pakker som ofte betegnes som “protestware”, da de inneholder logikk som utfører handlinger dersom brukerne kan geolokaliseres til spesifikke land. Pakken “peacenotwar” er et slikt eksempel, som ble lagt til som en avhengighet til node-ipc som er en mye brukt pakke. Dette resulterte i at peacenotwar også ble lastet ned hos mange brukere; de som ble geolokalisert til Russland eller Belarus fikk data slettet og ble utsatt for DOS-angrep via pakken.
Uavhengig av om noe er ment som malware eller protestware er konsekvensene alvorlige, og alle utviklingsprosjekter bør ha på plass tiltak for å begrense risiko og konsekvens dersom en hendelse inntreffer.
Bruk av CDN
Content-delivery-networks for å distribuere Javascript-bibliotek har blitt brukt av mange som en enkel måte å inkludere disse i koden uten å måtte inkludere dette i build eller deploy-prosessen. Tanken er god, men du får da en direkte avhengighet til en kilde du ikke har noen kontroll på som kan misbrukes til å spre malware.
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 vi avhenger av representerer en økning i kompleksitet og angrepsflate, og øker sjansen for at noe skjærer seg på et senere tidspunkt.
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. 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.
Interne speil og fork av kritiske avhengigheter
For spesielt kritiske avhengigheter kan det være riktig å hoste artefakter i interne registre eller bruke fork av pakker, actions og andre byggkomponenter. Dette reduserer eksponering mot hendelser hos tredjepart, men øker samtidig forvaltningsansvaret internt.
Dette bør brukes selektivt, typisk når avhengigheten er forretningskritisk, har høy påvirkning ved kompromittering, og teamet faktisk har kapasitet til å forvalte den over tid.
Hvis dere velger denne tilnærmingen, bør dere minimum ha:
tydelig eierskap for vedlikehold, patching og oppdateringsfrekvens
rutiner for å hente inn og verifisere nye upstream-versjoner
sporbarhet på hva som er intern kopi/fork, og hva som er original kilde
samme krav til skanning, lisenskontroll og review som for øvrige avhengigheter
Bruk av SBOM
Software Bill Of Materials (SBOM) er en tilnærming der vi genererer en oversikt over alle avhengigheter med versjoner fra løsningene våre. Denne oversikten bør knyttes til hver release, slik at det er tydelig hvilke avhengigheter som faktisk var i bruk på et gitt tidspunkt.
For KI-løsninger bør oversikten også inkludere relevante AI-artefakter som modeller, modelldigests, tokenizers og sentrale datasett-referanser der dette er relevant. Det finnes flere mer eller mindre standardiserte filformater for SBOM, og de kan arkiveres eller legges inn i andre løsninger for å forenkle monitorering fra sentralt hold.
God dokumentasjon er avgjørende for kontinuitet, etterprøvbarhet og sikkerhet. Det gjelder valgene som er tatt, trusler som er vurdert, og systemets faktiske oppførsel – også i AI-systemer.
Dokumentasjon er ofte nedprioritert under leveranse, men manglende dokumentasjon skaper reell risiko. Kildekode beskriver hvordan noe fungerer, men ikke hvorfor valg ble tatt, hvilke trusler som er vurdert, eller hvilke forutsetninger løsningen er avhengig av.
Sikkerhetskontekst som kun finnes i hodet på enkeltpersoner er en sårbarhet. Sikkerhetsmekanismer som ikke er dokumentert risikerer man at fjernes uten at noen forstår konsekvensen. Trusselmodeller som ikke er skrevet ned kan heller ikke vedlikeholdes eller revideres.
God dokumentasjon gir teamet mulighet til å vurdere risiko over tid, ikke bare ved ferdigstilling.
Dokumentasjonsløsning
Teamet må velge en løsning som faktisk brukes. Dokumentasjon som lever i et verktøy ingen åpner, gir liten verdi.
Populære tilnærminger inkluderer docs-as-code, der dokumentasjon skrives i Markdown og versjoneres i git ved siden av kildekoden. Dette gir lavere terskel for oppdateringer og full historikk over endringer.
Uansett løsning: husk at god dokumentasjon kan være like sensitiv som kildekoden. Trusselmodeller med åpne funn, arkitekturbeskrivelser og sikkerhetskonfigurasjoner må beskyttes på linje med systemet de beskriver.
Hva skal dokumenteres
Hva som må dokumenteres vil variere med prosjektets størrelse og kritikalitet, men følgende bør alltid være på plass:
Systemdesign: Skisser og diagrammer som viser infrastruktur, dataflyt, IAM og integrasjoner – på et nivå som gjør det mulig å ettergå arkitekturvalgene som er tatt.
Trusselmodell: Hvilke trusler er vurdert, hvilke tiltak er innført og hvilken restrisiko er akseptert. Trusselmodellen må vedlikeholdes og oppdateres ved endringer.
Sikkerhetskonfigurasjon: Konfigurasjoner som er sikkerhetskritiske skal dokumenteres, slik at de ikke utilsiktet endres eller utelates ved oppgradering og nyoppsett.
Hendelseslogg og avvik: Sikkerhetshendelser og avvik bør loggføres og dokumenteres, inkludert hva som ble gjort og hvilke læringspunkter som ble identifisert.
Kritiske avhengigheter: Eksterne tjenester, tredjepartsbiblioteker og integrasjoner som løsningen er avhengig av for korrekt sikkerhetsfunksjon.
Kritikaliteten til løsningen legger føringer for dybden: et system med 24/7-krav og høy konsekvens ved nedetid trenger mer detaljert dokumentasjon enn et internt lavrisikosystem.
Dokumentasjon av KI-systemer
KI-systemer stiller krav til dokumentasjon som tradisjonell teknisk dokumentasjon ikke fullt ut dekker. Modeller, treningsdata og evalueringsresultater endres over tid og påvirker systemets oppførsel på måter som ikke alltid er synlige i kode alene.
Følgende bør dokumenteres for løsninger med KI-komponenter:
Systemformål og tiltenkt bruk: Hva systemet er designet for å gjøre, hvem det er ment for, og hvilke bruksscenarioer som er utenfor scope.
Modellbeskrivelse: Hvilken modell brukes, hvem som har utviklet den, hvilken versjon og hvilken arkitektur. Dersom modellen er egentrent: treningsoppsett og metodikk.
Treningsdata og dataopphav: Beskrivelse av hvilke data modellen er trent på, inkludert kilder, lisensiering, eventuelle begrensninger og kjente svakheter i datagrunnlaget.
Evalueringsresultater: Dokumenterte målinger på ytelse, nøyaktighet, robusthet og eventuelle bias-funn. Evalueringsgrunnlag og metrikker bør beskrives slik at resultatene kan reproduseres og sammenlignes over tid.
Risikovurdering: Hvilke risikoer er identifisert knyttet til modellens oppførsel, og hvilke tiltak er innført. Dette inkluderer risiko for feilklassifisering, hallusinasjoner, urettferdig behandling og misbruk.
Menneskelig oversikt og grenser for autonomi: Hvor og hvordan mennesker involveres i beslutninger, og hvilke begrensninger som er lagt på hva systemet kan gjøre autonomt.
Endringsstyring: Hvordan modellversjoner styres, testes og rulles ut. Endringer i modell, treningsdata eller konfigurasjon bør spores og begrunnes.
Minimumsmal for KI-dokumentasjon
For å gjøre dette praktisk og konsistent kan teamet bruke en enkel minimumsmal per modellversjon eller vesentlig endring:
identifikator: modellnavn, versjon, dato og ansvarlig
formål og scope: hva modellen er godkjent for, og hva som er utenfor scope
datagrunnlag: kilder, avgrensninger, lisens og kjente svakheter
evaluering: testsett, metrikker, resultater og baseline-sammenligning
risiko og tiltak: sentrale funn, kompenserende kontroller og restrisiko
godkjenning: beslutning, godkjenner og eventuelle vilkår for produksjonsbruk
observabilitet: hva som logges/overvåkes i drift og hvilke terskler som utløser oppfølging
Malen trenger ikke være omfattende, men den bør være lik hver gang slik at sammenligning, revisjon og gjenbruk blir enkelt.
Denne dokumentasjonen er nødvendig både for intern kontroll og for å kunne demonstrere etterlevelse overfor kunder, tilsynsmyndigheter og andre interessenter.
Alle utviklingsprosjekter har behov for hemmeligheter som connection strings, identiteter, passord, sertifikater og annet. Disse må oppbevares på en trygg måte, og vi må sikre at vi bruker dem i en sikker kontekst med riktige støtteverktøy og prosesser.
Hemmeligheter er representert i utviklingsprosjekter i form av connection strings, passord, nøkler, sertifikater og alt annet som regnes som sensitiv informasjon vi ikke ønsker at andre skal få kjennskap til.
Det finnes mange ulike tilnærminger til hvordan disse skal håndteres, og dette har også endret seg etter hvert som nye tjenester dukker opp. For skyløsninger har tjenester som Azure Key Vault og liknende nærmest blitt en standard, da disse tjenestene håndterer flere aspekter av hvordan en bruker og forvalter hemmeligheter.
Grunnprinsipper for håndtering av hemmeligheter
Hemmeligheter skal aldri hardkodes eller sjekkes inn i versjonskontrollsystemer
Verifiser etterlevelse ved å skanne koden - avvis commits med hemmeligheter og roter disse øyeblikkelig!
Ha kontroll på hvilke hemmeligheter du har og hvilke tilganger disse har
Begrens levetiden på hemmelighetene - ingen hemmeligheter bør leve mer enn et år, passord og nøkler mye kortere
Teammedlemmer bør ikke ha tilgang til alle hemmeligheter alltid, elever eller legg på tilgang ved behov
Hemmeligheter og KI-verktøy
Når KI-verktøy brukes i utviklingsløpet, oppstår nye måter hemmeligheter kan bli eksponert på.
Hemmeligheter i prompt og kontekst
KI-verktøy som Copilot, Claude eller andre kopierer gjerne større deler av kodebasen for å forstå konteksten. Hvis repoet inneholder hardkodede hemmeligheter, eksempel-konfigfiler med ekte verdier eller testdata med passord, risikerer du at disse sendes til KI-tjenestens servere. Dersom dette skjer er sjansen stor for at det er et brudd på avtalen med kunde, i tillegg til at det alltid er en mulighet for at KI-verktøyet kan forsøke å koble til. Dersom du mangler andre sikkerhetsbarrierer kan det i verste fall resultere i at data endres eller påvirkes på annet vis.
Hovedregel
Lim aldri hemmeligheter, tokens eller ekte credentials i prompt, selv ikke når du debugger eller spør om hjelp.
KI-generert kode som logger hemmeligheter
Det er ikke uvanlig at KI-verktøy hallusinerer eller lager kode som ikke følger beste praksis. En må være spesielt årvaken for å fange opp tilfeller der KI-generert kode lagrer sensitiv informasjon som hemmeligheter, databasespørringer eller konfigfiler i logger.
Før kjøring er det viktig at KI-generert kode sjekkes grundig:
logges eller skrives det sensitiv data til stdout?
legges det hemmeligheter i cache eller midlertidige filer?
vises hemmeligheter som del av feilmeldinger?
Redusert tilgang og exclusions
Noen KI-verktøy som GitHub Copilot tilbyr content exclusion, slik at du kan utelukke mapper eller filtyper fra å leses av verktøyet. Bruk dette for å hindre at hele konfigfiler eller testdata sendes til KI-tjenester. Dette bør ikke være den eneste sikkerhetsbarrieren som hindrer at KI-verktøyene får tilgang på hemmeligheter, men kan være en mekanisme som gir deg et ekstra lag med sikkerhet.
Rotasjon av hemmeligheter
Hemmeligheter som har vært tilgjengelige for KI-verktøy, logger, lagt i kildekode eller på annet vis eksponert for andre skal roteres. Det er ikke nok å fjerne hemmeligheten eller håpe på at ingenting går galt; dersom den har blitt eksponert skal du alltid anta at den kan utnyttes. Dette gjelder også sertifikater, nøkler og annet.
Kryptografi og hashing
Kryptografi og hashalgoritmer er komplekse tema, og det krever store ressurser og mye kompetanse for å bygge gode algoritmer som er sikre. Av denne enkle grunn skal du aldri lage egne, uansett hvor finurlig og sikker den ser ut til å være.
Det du derimot skal gjøre, er å:
Sette deg inn i best-practices for ditt programmeringsspråk, rammeverk og plattform
Sikre at du ikke bruker sårbare algoritmer som f.eks. SHA1, MD5 eller DES
For kryptografi; sett deg inn i hvilke anbefalinger som gjelder for nøkkellengder og anbefalinger ift bruk
Husk
Hemmeligheter skal aldri sjekkes inn i kildekodesystemet!
På linje med annen elementer assosiert med teamet kvalitet er vi avhengige av å kunne teste for å verifisere at vi har oppnådd målet. Sikkerhetstesting er et viktig ledd i dette, da vi gjennom testingen kan vise at leveransen ikke er sårbar for gitte angrepsmetoder.
Sikkerhetstesting bør alltid være et element av alle leveranser. Mange assosierer sikkerhetstesting med penetrasjonstesting, men det er mye mer enn dette. Noen former for testing kan gjøres automatisk som del av CICD, andre er mer manuelle og skjer typisk mot en deployert løsning.
Før en setter i gang med sikkerhetstesting er det viktig å sette seg inn i hva dette kan gi deg - det finnes ingen enkelttiltak som løser alle sikkerhetsproblemer, og heller ingen enkelt testmetode som avdekker alle svakheter. Sikkerhetstesting er også et av områdene som ofte krever spesifikk kompetanse for at resultatene skal bli gode og/eller tolket korrekt.
Advarsel
Bruk av verktøy som nmap og annet som brukes i forbindelse med sikkerhetstesting må alltid avklares med eiere av infrastruktur og nettverk, da det er vanskelig å skille vennligsinnet testing fra ondsinnede angrep. Dette gjelder også internt i Bouvet; Intern-IT & Sikkerhet skal alltid være i loopen før du starter en sikkerhetstest!
Dersom dette ikke tas hensyn til kan det få konsekvenser, både for kundeforholdet men også for tekniske løsninger mot nettleverandør og Microsoft.
Testmiljø
Når en skal bedrive sikkerhetstesting mot et kjørende miljø er det viktig at en alltid avklarer dette godt i forkant. Mange typer testing kan være destruktiv, så dersom miljøene ikke er godt nok adskilt kan en risikere å påvirke andre miljø enn tiltenkt.
En god løsning, spesielt dersom en bruker infrastruktur-som-kode (IAC) er å ha en pipeline som deployer et eget miljø som kan brukes for sikkerhetstesting. Dersom dette designes inn i leveransen fra starten, vil det ofte være enkelt å sette opp miljø som er identiske med produksjonsmiljøet, der en også kan kopiere databaser og eventuelt kjøre anonymiseringsprosesser mot dataene.
Statisk kodeanalyse (SAST)
Statisk kodeanalyse er et lavterskelteknikk som analyserer koden med avhengigheter for å finne svakheter. SAST kan gjennomføres helt automatisk, og det finnes mange gode verktøy som kan bygge dette inn i CICD slik at du kan skanne som en del av prosessene her.
SAST sjekker kun løsningen som lages, den avdekker ingenting rundt konfigurasjon av kjøremiljø, nettverk eller andre omkringliggende avhengigheter. Verktøy som brukes for å gjennomføre SAST er språkspesifikke, så det er viktig å sette seg inn i hvilke verktøy som gir best resultat for språk og eventuelt rammeverk som benyttes.
Dynamisk applikasjonssikkerhetstesting (DAST)
I motsetning til SAST er DAST en teknikk der en tester en løsning i kjørende tilstand. Dette er en språkagnostisk testmetode, der en eksempelvis tester en webapplikasjon gjennom å teste frontendløsningen for å finne svakheter. DAST kan automatisers, men må ofte kjøres manuelt for at enkelte typer svakheter skal testes.
DAST vil kun dekke funksjonalitet eksponert i den kjørende løsningen, så dersom en har kode som er en del av løsningen men som ikke er tilgjengelig for DAST-verktøyet vil dette heller ikke kunne testes.
Sikkerhetstesting av AI-systemer
Løsninger som bruker kunstig intelligens introduserer sikkerhetstestingsbehov som går utover tradisjonell SAST og DAST. AI-systemer må valideres for at de oppfører seg som forventa og at de ikke introduserer nye sårbarhetsvektorer.
Validering av AI-modeller
AI-modeller skal valideres for:
Nøyaktighet og ytelse: Modellen skal oppfylle definerte kvalitetskrav under forventede bruksforhold
Bias og fairness: Tester for å avdekke om modellen diskriminerer basert på sensitive attributter
Robusthet: Testing av hvordan modellen oppfører seg ved uventet eller adversariell inndata
Hallusinasjoner: Verifisering av at modellen ikke genererer falsk informasjon eller usikre mønstre
Validering av AI-modeller krever ofte domene-spesifikk kompetanse og bør være en del av ansvaret til datalagene og ML-teamet, ikke bare infosikkerhet.
Sikkerhetstesting av AI-komponenter
I tillegg til modellvalidering må løsningen som helhet testes for:
Prompt injection: Tester for om inndata kan manipulere AI-agenten til å oppføre seg uventet
Dataeksfiltrering: Verifisering av at sensitive opplysninger ikke blir ekstrahert via prompts eller outputs
Tillitsgrenser: Testing av hvordan systemet oppfører seg når AI-assistansen overskrider sine definerte grenser
Disse truslene må håndteres med samme rigor som tradisjonelle applikasjonssikkerhetstester. For prosjekter med KI-komponenter bør teamet bruke OWASP Top 10 for LLM Applications som grunnlag.
Penetrasjonstesting
En penetrasjonstest går dypere enn SAST og DAST ved å teste systemet som en helhet, inkludert infrastruktur, nettverk og muligens også fysisk sikring. Der DAST primært fokuserer på webapplikasjoner, vil en pentest være mer omfattende og ofte avdekke sårbarheter som bare blir synlige når flere trusler kombineres.
En penetrasjonstest vil alltid ha et avtalt omfang som regulerer hva pentesterne kan gjøre, når de kan gjøre det og hvilke ressurser som kan testes. Det er ikke mulig å bevise at en løsning er sikker, kun at den ikke er sårbar mot gitte angrep. Pentesting er derfor særlig nyttig når løsningen har strenge sikkerhetskrav eller opererer innenfor et avtaleverk som krever uavhengig verifisering.
Planlegging og omfang
En pentest krever kompetanse og skal ikke gjennomføres på egen hånd uten relevant erfaring. Som team må dere sikre at miljøet som skal testes er tydelig identifisert, og at omfanget er godt definert før testingen starter. Det må være mulig å skille et faktisk angrep fra en avtalt test. Dersom du ser tegn på aktivitet mot et miljø som ikke er en del av testen og dere har segregert miljøene, bør dette håndteres som en reell hendelse.
Som en del av planleggingen må dere også avklare kundens rutiner for pentesting. Mange virksomheter har et sikkerhetssenter (SOC) og/eller nettverkssenter (NOC) som overvåker infrastrukturen kontinuerlig. Disse må være informert når testen er varslet, slik at en avtalt test ikke utløser unødvendig eskalering.
I noen tilfeller ønsker kunden en uvarslet test for å se om angrepet oppdages. Det må i så fall være eksplisitt avtalt, siden en pentest i praksis er et simulert angrep.
Når pentest er aktuelt
I en perfekt verden ville en gjennomført pentest ved alle større endringer, men dette er sjelden praktisk. Hvor ofte testen skal gjennomføres avhenger av kundekrav, regulatoriske føringer og hvor mye risiko løsningen bærer. Dette bør avklares tidlig, ikke først når dere ønsker å bestille en test.
Oppfølging under og etter test
Dersom testen er varslet i forkant, er det en god anledning til å følge med på logger og monitorering for å se om hendelsene blir fanget opp. Dersom funnene i rapporten kan korreleres med det dere observerer i logger og alarmer, gir det et godt grunnlag for å forbedre deteksjon og varsling.
Etter testen vil teamet normalt motta en rapport som beskriver hva som er testet, hvordan testen ble gjennomført og hvilke funn som ble gjort. Funnene må gjennomgås med produkteier, klassifiseres og legges i backloggen. Noen funn må lukkes raskt, mens andre kan aksepteres eller planlegges senere dersom andre tiltak reduserer risikoen. Sikkerhet er ikke et individuelt ansvar; det er teamets ansvar å følge opp kravene som gjelder for løsningen.
AI-fokuserte penetrasjonstester
Dersom løsningen inkluderer AI-komponenter, bør pentestingen også dekke:
Testing av API-sikkerhet rundt AI-modellen
Endrings- og versjonskontroll av modeller og treningsdata
Logging og overvåking av AI-systemets oppførsel
Tilgangskontroll til sensitive modeller og data
For løsninger med AI-komponenter bør pentestingen også vurdere prompt injection, manipulering av kontekst, uautorisert tilgang til modellkall og om modellen kan brukes til å hente ut sensitiv informasjon som systemet ellers ikke ville eksponert.