- COMP.SEC.100
- 16. Ohjelmistoturvallisuus
- 16.2 Haavoittuvuuksien havaitseminen
Haavoittuvuuksien havaitseminen¶
Mitä varhaisemmin haavoittuvuus havaitaan ja pystytään korjaamaan, sitä kustannustehokkaampaa se on, mutta haavoittuvuuksia on joka tapauksessa tarpeen tunnistaa eri ohjelmistokehityksen vaiheissa: suunnittelu, toteutus ja ylläpito.
Tunnistustekniikan sanotaan olevan varma (sound), jos se pystyy täydellisesti päättelemään, että määritettyä haavoittuvuutta (tai joukkoa haavoittuvuuksia) ei ole tutkitussa kohteessa. Epävarma tunnistus puolestaan ei löydä kaikkia määriteltyjä haavoittuvuuksia.
Tunnistustekniikan sanotaan olevan täydellinen (complete), jos tekniikan löytämä haavoittuvuus on todella haavoittuvuus. Toisin sanoen tällöin ei tule virheellisiä ilmoituksia (false positives) haavoittuvuuksista, jotka eivät todellisuudessa ole haavoittuvuuksia.
Staattinen analyysi (syventävä)¶
Staattisessa analyysissa tutkitaan ohjelmakoodia tai binäärikoodia suorittamatta sitä. Tällöin etuna on, että ohjelman ei tarvitse olla valmis ja toisaalta pystytään tarkistamaan koko ohjelmakoodi. Staattiseen analyysiin voidaan katsoa kuuluvan myös ihmisten tekemät koodikatselmoinnit (code review). Koodikatselmoinnilla on paikkansa, koska ihminen pystyy hahmottamaan ohjelman toiminnan kokonaisuutena ohjelmaa paremmin. Toisaalta valmiit ohjelmat eli staattiset analysaattorit löytävät ihmistä tehokkaammin yleisiä tiedossa olevia ongelmia. Staattinen analyysi voidaan jakaa heuristiseen tunnistamiseen (heuristic static analysis) ja varmuusanalyysiin (sound static analysis).
Heuristinen tunnistaminen perustuu sääntöihin, joilla pyritään tunnistamaan virheet koodista. Esimerkiksi tietyt turvattomat koodaustavat, taulukoiden yli-indeksointi tai turvattomat rajapintojen kutsut saatetaan tunnistaa. Analysaattori voi myös rakentaa mallin ohjelmasta ja sen tietovirroista pyrkien näin tunnistamaan yksittäisiä virheitä laajempia kokonaisuuksia.
Siinä missä heuristinen tunnistaminen pyrkii osoittamaan jonkin tunnetun virheen tai sen variaation, varmuusanalyysi pyrkii osoittamaan, että virhettä ei ole. Varmuusanalyysissa pyritään formaalin menetelmin osoittamaan koodin turvallisuus joiltain osin, kuten oikea muistinkäsittely. Varmuusanalyysin ideana on, että jos ohjelmassa on tietty ennalta tunnettu virhe, se myös löydetään. Käytännössä näihin yleviin tavoitteisiin on kuitenkin tehtävä kompromisseja, joten kaikkia virheitä ei ole mahdollista löytää.
Staattinen analyysi ei siis löydä kaikkia virheitä. Ne saattavat myös antaa paljon virheellisiä ilmoituksia (false positives), mikä voi tehdä ohjelman käytöstä työlästä ja virhealtista. Paljon riippuu ohjelmasta ja sen käytöstä. Staattiset analysaattorit ovat luonnollisesti sidottu tiettyyn ohjelmointikieleen. Staattiset analysaattorit ovat joka tapauksessa yksi erittäin tärkeä työkalu turvallisessa ohjelmistokehityksessä. Yrityksessä saattaa esimerkiksi olla vaatimuksena, että ohjelman on läpäistävä tietyt valitut staattiset analysaattorit ilman vakavia virheitä.
Dynaaminen analyysi (syventävä)¶
Dynaamisessa tunnistuksessa havainnointi tehdään ohjelman suorituksen aikana. Dynaamisella tunnistuksella on mahdollista estää haavoittuvuuden aiheuttama ongelma jopa ohjelman suorituksen aikana. Näin toimittaessa kuitenkin ohjelman suorituskyky alenee.
Monitorointi (syventävä)¶
Monitoroinnissa seurataan ohjelman suoritusta ajon aikana. Monitoroinnilla on periaatteessa mahdollista estää haavoittuvuudet täydellisesti. Tämä tapahtuisi kuitenkin niin kovalla suorituskyvyn alenemisella ja muistin tarpeella, että käytännössä joudutaan tekemään kompromisseja.
Nykyiset C/C++ -kääntäjät sisältävät mahdollisuuden lisätä monitorointia kääntämisen aikana, jolloin ohjelma havaitsee ja estää ajonaikaisia muistinhallinnan virheitä automaattisesti.
Syötteen monitoroinnissa ongelma on, että syöte ja tuloste ovat usein turvallisuuden näkökulmasta monitoroivalle ohjelmalle määrittelemättömiä.
Kilpatilanteiden monitorointi on vaikeaa, mutta joissain tapauksissa muistin jakamista on mahdollista monitoroida ja tarkistaa, että oikeudet eivät aiheuta ristiriitaa.
Yksi tärkeä tapa löytää haavoittuvuuksia on löytää ohjelman suorituspolut ja oikeat syötteet. Tähän auttaa Fuzz-testaaminen, jolla pystytään tuottamaan automaattisesti erittäin suuri määrä testaussyötettä. Ohjelman saaman syötteen mukana tulee suuri joukko viallista ja ennalta-arvaamatonta syötettä. Testausohjelma myös dokumentoi ohjelman mahdollisen viallisen käyttäytymisen, jolloin virheitä pystytään jäljittämään.
Fuzz-testaus voidaan jakaa mustan ja valkoisen laatikon testauksiin:
Mustan laatikon testauksessa ei käytetä lähdekoodia, joten testaus ei perustu ohjelman rakenteen tuntemiseen. Mustan laatikon testaus voidaan jakaa kolmeen tapaan:
- Aidosti satunnainen
- Satunnainen, mutta on otettu jokin arvoalue. Käytetään myös käsitettä parametrisointi.
- Mutaation perustuva, jolloin annetaan jokin alkusyöte, jota testausohjelma alkaa muuttamaan eli muodostamaan mutaatiota.
Valkoisen laatikon testauksessa lähdekoodi auttaa testausohjelmaa tunnistamaan syötealueita ja ohjelman haarautumista. Näin ohjelma pystyy löytämään mustan laatikon testausta sopivamman testausdatan, joka kattaa mahdollisia virhesyötteitä paremmin. Tästä tuleekin englanninkielinen termi ”coverage based fuzzing”.