Risikobasert sikkerhetstesting

Sikkerhetstesting tar for seg artefaktene enheter og komponenter snarere enn systemet som helhet. Det er en blanding av en “hvit-hatt” og en “svart-hatt” tilnærming, og kan gjøres fra utsiden og inn, eller fra innsiden og ut. Sikkerhetstesting drives av misbrukseksempler (misuse cases/abuse cases), og omfatter to strategier: Testing av sikkerhetsfunksjonalitet, og risikobasert testing basert på angrepsmønster.

Målet med sikkerhetstesting er å unngå at fæle ting skal skje. Sikkerhetstesting tar utgangspunkt i arkitekturen, og prøver vanlige angrep ved å ta i bruk mentaliteten til en angriper. Testeren vil i utgangspunktet ha tilgang til all informasjon om koden som skal testes, og vil bruke dette til sin (“angriperens”) fordel.  Sikkerhetstesting kan gjøres før programvaren er ferdig, og kan utføres på modulnivå i testmiljø for hver leveransesyklus. Sikkerhetstesting vil fokusere på de verdifulle egenskapene til applikasjonen som en angriper eventuelt kunne ønske å tukle med. Dette kan omfatte data (konfidensialitet, integritet og tilgjengelighet; personvern; immaterielle rettigheter), tid (produksjonsforsinkelse; prosesseringsforsinkelse; tid til markedet), penger (kundeklager; tapt inntekt), renomme og merkevare (tap av tillit), og juridiske forhold (etterlevelse av lover og regler, kontraktuelle forpliktelser). Det vil variere fra applikasjon til applikasjon hvilke av disse som er aktuelle.

Som leseren sikkert husker, deler vi sikkerhetsfeil i to klasser, implementasjonsfeil (bugs) og designfeil (flaws). Implementasjonsfeil omfatter lavnivå sårbarheter og bufferoversvømmelse, men også mer applikasjonsnære sårbarheter som SQL-injisering og Cross-site scripting. Utrygg omgang med formatstrenger og generell injisering av kode (ikke bare SQL-spørringer) er også med på lista, og selvfølgelig bruk av risikable systemkall som scanf()  (mange mener at det å programmere i C er risikabelt i seg selv – og vi skal ikke unnslå at med stor makt følger det stort ansvar). McGraw nevner også kappløpstilstander (race conditions) som implementasjonsfeil, selv om disse ikke er så lette å avdekke vha. statisk kildekodeanalyse.  Kappløpstilstander er noe man risikerer når man opererer med samtidighet, der flere prosesser kan gjøre endringer i variable samtidig. Dersom man ikke er nøye, risikerer man at man leser en variabel lenge før den brukes, og når man bruker den til å foreta et valg, har den allerede endret seg (også kjent som TOCTOU). Det finnes selvfølgelig massevis av andre eksempler!

Under designfeil finner vi feil i sesjonshåndtering, aksesskontrollister og TLS-implementering (her stod det opprinnelig “SSL/TLS”, men per i dag må vi nok påpeke at det å implementere SSL er en designfeil i seg selv – det er ikke noen grunn til å velge noe dårligere enn TLS 1.3). En annen klassiker er malplassert tillit til tredjepartssystemer (og manglende oppdatering av tredjepartsbiblioteker).

Betydningen av hatter

I amerikanske cowboy-filmer i første halvdel av forrige århundre, vokste det fram en «regel» om at de «snille» rollene gikk med hvit hatt, og de «slemme» hadde svart hatt. I sikkerhetsverdenen har mange valgt å bruke samme merkelappen, og man kunne være fristet til å snakke om “hvit-hatt-teknologi-entusiast” (White Hat Hacker) og “svart-hatt-teknologi-entusiast” (Black Hat Hacker) – men jeg er redd det rett og slett blir for kronglete på norsk.

For å komplisere det enda mer, har man også en annen bruk av hvit og svart i dataverdenen, når man snakker om “hvit boks” og “svart boks” i forbindelse med analyse eller utvikling. Hvis du gjør en svart-boks-analyse av en komponent, har du ingen informasjon om hva som skjer inni komponenten; du kan dytte data inn og få data ut, men det er det eneste du vet. Gjør du en hvit-boks-analyse derimot, har du full oversikt over alle interne prosesser i komponenten; du har sannsynligvis mulighet for å inspisere hver enkelt kodelinje, tilgang på internt minne, operativsystem, osv.

Hvit-hatt kontra svart-hatt-tilnærming

Hvis man har den hvite hatten på, har man full kjennskap til alle de interne detaljene i systemet, og kan bruke denne kunnskapen til å lage tester og konstruere testdata. Kunnskapen kan også brukes når man skal analysere resultatene.

Med den svarte hatten på, har man lite eller ingen informasjon om systemet, og betrakter det som en svart boks. Man tar så utgangspunkt i funksjonaliteten som systemet tilbyr, og gjør hva man kan for å misbruke det man kan.

Sikkerhetstesting av applikasjoner

Når man driver med sikkerhetstesting av applikasjoner, omfatter dette to forskjellige tilnærminger. Den første er funksjonell testing av sikkerhetsfunksjonalitet, hvor man verifiserer at sikkerhetsmekanismer faktisk fungerer som de skal – dette skiller seg ikke så mye fra annen funksjonell testing.

Den andre tilnærmingen er angrepsorientert sikkerhetstesting, hvor man tester ikke-funksjonelle og negative krav. Målet er å verifisere sikkerhetsmål som man gjør det i trusselmodellering, og eventuelt oppdage sårbarheter som har blitt introdusert i arkitekturbeslutninger eller programmering.

Funksjonell sikkerhetstesting er basert på (forhåpentligvis nedskrevne) sikkerhetskrav, og er koblet til applikasjonens sikkerhetsfunksjonalitet. Dette utføres gjerne som en del av kvalitetskontrollen som utføres av dedikerte testere.

Et naturlig utgangspunkt for sikkerhetstesting er etablerte misbrukseksempler (misuse case/abuse case), hvor man legger til negative tester og bruker angriperens tankesett for å prøve å utnytte, misbruke eller omgå sikkerhetsmekanismer.

Risikobasert sikkerhetstesting fokuserer på identifisert risiko. For å danne seg et realistisk risikobilde, er det nødvendig å gjøre grundig forarbeide. Dette kan omfatte trusselmodellering (inkludert McGraws utvidelser som omfatter tvetydighetsanalyse og underliggende rammeverk), bruk av misbrukseksempler (), angrepsmønstre, og en solid forståelse av hele systemet (datastrukturer, komponenter, API, programtilstander, osv.).

Risikobasert sikkerhetstesting benytter seg av all denne informasjonen, og bruker den for å planlegge og utføre tester for å avdekke feil som representerer en sikkerhetsrisiko. Sikkerhetstesting blir mest effektiv når den er informert av trusselmodellering, slik at det er mulig å rangere truslene og prioritere deretter.

En tilnærming til risikobasert sikkerhetstesting (RBST) involverer å avgjøre hvem som skal utføre testene, og hvilke aktiviteter som skal gjennomføres. Tradisjonelle kvalitetssikrere kan sannsynligvis utføre funksjonell testing av sikkerhetsmekanismer like bra som for annen funksjonalitet, men angrepsorientert sikkerhetstesting forutsetter en dypere sikkerhetskompetanse for å lykkes. RBST-prosessen omfatter å beskrive alle krav basert på risikoen som er involvert i prosjektet, prioritere kravene som en del av risikovurderingen, planlegge og definere testene i henhold til prioriteringslisten, og endelig utføre testene i prioritert rekkefølge og i henhold til akseptansekriteriene for programvaren.

For at noe skal være risikobasert, er det en forutsetning at man har gjort en risikoanalyse først. En tilnærming til dette er å dokumentere hver enkelt forretningsrisiko, og så knytte hver distinkt forretningsrisiko til alle relevante tekniske risikoer. Høynivå tekniske risikoer kan dekomponeres i mer detaljerte tekniske risikoer, og man kan tilordne sannsynlighet og konsekvens (og dermed risikonivå) til hver av dem. For hver av disse kan man så spesifisere en eller flere sikkerhetstester (eller angrep) som man kan rangere etter prioritet, som illustrert i Tabell 1.

Tabell 1: Prioritert testplan (utdrag)

Forretningsrisiko:BR5: Tap av tiltro til resultater  
Test ID Relatert risikoPriAngrep
SEC-2 TR2-1: Manipulerte stemmer (SQLi)  
 SEC-2.1 2Sjekk ‘OR 1=1
 SEC-2.2 2Sett inn meta-tegn i forespørsel
 SEC-2.3 1Automatisert fuzzing
  
SEC-3 TR3.1: Råtten autentisering – svake passord  
 SEC-3.1 1Finnes passordpolicy?
 SEC-3.2 2Prøv å angi svakt passord
  

Hvorfor er det gunstig med en risikobasert testplan? Den vil gjøre det mulig å strukturere og planlegge testene, og potensielt identifisere unødvendige tester som kan fjernes. Den vil også gjøre det mulig å prioritere, og til syvende sist sette deg i stand til å gjøre et informert valg når det kommer til å akseptere en eventuell restrisiko. Ikke glem at man både må teste funksjonaliteten til sikkerhetsmekanismer og gjøre angrepsorienterte tester for å avdekke andre sårbarheter.

Integrering med andre trykkpunkter

For best resultat må man ta med seg innsikt og erfaringer fra andre aktiviteter i programvaresikkerhetsarbeidet. Aktiviteter som trusselmodellering, statisk analyse og kodegjennomgang har et innenfra-og-ut perspektiv som bidrar til å gjøre både sikkerhetstesting og penetreringstesting mer effektivt. Testing kan avgjøre om en oppdaget svakhet i en tidligere fase lar seg utnytte i et praktisk angrep. Dette vil også bidra til økt sporbarhet ved å koble forretningsrisiko via teknisk risiko til enkelttester (eller angrep). Dette kan videre gi innspill til praktiske hendelseshåndteringsplaner.  

Illustrasjon ved RF._.studio from Pexels