Salasanat talteen turvallisesti
7 helmi 2013
Surullisen usein saa uutisista lukea tietomurroista, joissa on viety tuhansien käyttäjien salasanat. Hyvää tietoturvakuria noudattavan IT-ammattilaisen on helppo vähätellä tietovuotoa.
Ihmisillä on kuitenkin tapana käyttää samaa salasanaa useaan palveluun ja ihan ymmärrettävästä syystä. Kun on kerran opetellut ulkoa hyvän salasanan, on suuri houkutus käyttää sitä joka palvelussa.
Lue miten voit varmistaa, ettei sinun palvelusi paljasta käyttäjiesi salaisuuksia.
Minimoi vahinko ennakkoon
Web palvelun ylläpitäjä ei ikävä kyllä (ainakaan eettisin keinoin) pysty pakottamaan käyttäjiään valitsemaan eri salasanaa kuin muissa palveluissa, ja tiukat rajoitteet salasanan vähimmäispituudelle vain kannustavat uudelleenkäyttöön. Harva jaksaa muistaa ulkoa kovin montaa numeroita ja erikoismerkkejä sisältävää kirjainsotkua.
Ylläpitäjän onkin vain hyväksyttävä, että iso osa käyttäjistä ei noudata hyviä tietoturvakäytäntöjä.
Ylläpitäjä voi vain tehdä parhaansa suojatakseen käyttäjien tiedot hyökkääjiltä.
Miten käyttäjien tunnuksia voi sitten suojella? Jos sokeasti luottaa järjestelmän hakkerinkestävyyteen, voi jonain päivänä vastassa olla ikävä yllätys. Järkevämpi ratkaisu on varautua murtoon ja minimoida sen seuraukset ennen kuin se tapahtuu.
Ensimmäinen virhe salasanojen säilytyksessä on tallentaa ne sellaisenaan selkokielisenä. Hakkeri voi napata koko listan yhdellä SQL injektiohyökkäyksellä. Selkokielisten salasanojen tallennukseen ei ole nykypäivänä tekosyytä.
Älä koskaan tallenna selkokielisiä salasanoja
Astetta parempi tapa on kryptata salasanat jollakin standardilla salausalgoritmilla (huom. ei omakeksimällä, ellet ole Bruce Schneier). Kryptatut salasanat ovat suojassa yksinkertaisilta hyökkäyksiltä, mutta tässäkin lähestymistavassa on ongelma: mikäli salasanoilla halutaan tehdä jotain (kuten yleensä halutaan), palvelimen pitää pystyä myös avaamaan ne. Jos hakkerilla on pääsy palvelimelle, voi hän löytää myös avaimen ja salauksen hyöty kadotetaan. Yleisesti ottaen ilman erittäin pätevää syytä säilyttää pääsy selvätekstisiin salasanoihin, ei kaksisuuntaista salausta tule käyttää.
Jos salasanoja ei kuulu tallentaa selvätekstisenä tai salattuna, niin miten sitten?
Vastaus on, että salasanojen sijaan tallennetaan niiden tiiviste (hash). Tiiviste, tai hajautusarvo, muodostetaan hajautusfunktiolla. Matemaattisesti ilmaistuna, hajautusfunktio on surjektio suuresta lähdejoukosta pieneen mallijoukkoon. Toisin sanottuna, hajautusalgoritmit ovat yksisuuntaisia, eli tiivisteestä ei pysty laskemaan alkuperäistä lähdettä.
Yksinkertaisin tapa on siis generoida käyttäjän salasanasta vaikkapa SHA1 tiiviste ja tallentaa se selvätekstin sijaan. Sisäänkirjautuessa käyttäjän syöttämästä salasanasta lasketaan myös SHA1 tiiviste ja jos se täsmää tallennetun kanssa, voidaan käyttäjä kirjata sisään. Yksinkertaista, mutta ei vielä tarpeeksi turvallista!
Pelkkä tiiviste ei takaa riittävää suojaa, sillä on olemassa valmiiksi laskettuja taulukoita (reverse lookup table, rainbow table) joista löytyy kaikkien yleisimpien salasanojen tiivisteet. Vapaasti ladattavia taulukoita löytyy mm. LM, MD5, SHA1 ja NTLM algoritmeilla suojattujen salasanojen murtamiseen.
Taulukko-ongelman voi ratkaista kahdella tavalla: vaaditaan käyttäjää syöttämään hyvin pitkä salasana tai käytetään suolaa (cryptographic hash.)
Pitkän salasanan vaatiminen saattaa olla jopa haitallista, koska se kannustaa ihmisiä kirjoittamaan salasanan ylös (yleensä näppäimistön alle piilotetulle tai näytön kylkeen liimatulle lappuselle) ja/tai käyttämään samaa salasanaa joka paikassa. Tarkastellaan siis teknistä ratkaisua, eli kryptografista suolaa.
Suola on satunnainen merkkijono joka lisätään salasanaan suurentamaan sen efektiivistä pituutta. Riittävän pitkä suola tekee taulukoinnista mahdottoman, koska jokainen lisäbitti tuplaa vaaditun hakutaulukon koon. Suola itsessään ei ole salaisuus, sillä sen ainoa tarkoitus on estää taulukointihyökkäys. Tämän takia jokaiselle salasanalle kannattaa generoida oma suola ja tallentaa se selvätekstisenä salasanatiivisteen ohelle.
Yksilölliset suolat korjaavat samalla toisen ongelman: sama salasana ei enää tuota samaa tiivistettä, joten pelkästään tietokantaa tarkastelemalla ei pysty sanomaan kenellä kahdella käyttäjällä on sama salasana.
Yksinkertainen tapa käyttää suolaa on tallentaa salasanatiiviste näin: suola + HASH(suola + salasana). Tarkistettaessa erotetaan suola tallennetusta tiivisteestä ja lasketaan uusi tiiviste suolan ja syötetyn salasanan avulla.
Suolattu kryptografinen tiiviste ei riitä
Suolan käyttö suojaa taulukoinnilta, mutta menetelmässä on edelleen yksi heikko kohta: kryptografiset tiivistefunktiot voidaan laskea erittäin nopeasti. Lyhyt salasana murtuu kokeilemalla kaikkia mahdollisia vaihtoehtoja (brute force), mutta jo kahdeksan merkkisiä kirjaimia (a-z) ja numeroja (0-9) sisältäviä salasanoja on 628 (n. 218 biljoonaa) kappaletta. Oli algoritmi kuinka nopea tahansa, on näin suuren vaihtoehtomäärän läpikäynti liian hidasta, ellei kyseessä ole kohdistettu hyökkäys tiettyä käyttäjätunnusta kohtaan. Opportunistisesti suuren salasanamäärän keräämiseen tarvitaan erilainen lähestymistapa.
Ihmiset usein valitsevat salasanaksi jotain helposti muistettavaa, mikä yleensä tarkoittaa, että salasana on variaatio jostakin sanakirjasta löytyvästä sanasta. Mahdollisesta 0,2 triljoonasta merkkijonosta vain hyvin pieni osa ovat oikeita englannin- tai suomenkielisiä sanoja, tai niiden variaatoita. Kokeilemalla pelkästään sanakirjan sanoja, mahdollisesti pienillä muutoksilla (pienet ja isot kirjaimet, leetspeak, loppuun 123, jne.) voikin löytää suuren määärän toimivia salasanoja. Tätä kutsutaan sanakirjahyökkäykseksi (dictionary attack.)
Suuressa sanalistassa voi olla jopa yli miljardi salasanaa. Nykykoneilla miljardi SHA1 laskua onnistuu kädenkäänteessä, etenkin jos hyödynnetään grafiikkakiihdyttimen laskentatehoa. Muutaman vuoden vanhalla PC:llä meni kymmnenen tuhannen SHA1 tiivisteen laskuun vain vajaa puoli sekuntia.
Harrastelijabudjetilla voi rakentaa erikoistuneen koneen joka kokeilee monta miljardia salasanaa sekunnissa.
Tämä uhka torjutaan vaihtamalla tiivistefunktion tilalle erityisesti salasanojen tiivistämiseen suunniteltu algoritmi, kuten PBKDF2 tai bcrypt. Nämä algoritmit ovat tahallaan suunniteltu hitaiksi, usein myös niin, että niille on vaikea suunnitella tehokasta rautakiihdytystä. Yleensä hidastus on toteutettu säädettävällä työkertoimella. Kun nopeampia tietokoneita saapuu markkinoille, voidaan työkerrointa kasvattaa ja uusien koneiden nopeusetu kumota.
Esimerkiksi saman 10000 salasanan setin PBKDF2 tiivisteiden lasku (työkertoimella 1000) vei suunnilleen vartin, eli melkein 2000 kertaa kauemmin kuin pelkkien SHA1 tiivisteiden laskeminen.
Oikealla algoritmilla tuotettu salasanatiiviste on siis hidas laskea, joten sanakirjahyökkäys ei ole tehokas. Se on suolattu, joten hakutaulukkohyökkäys on mahdoton. Ja tietysti, tiivistealgoritmi on valittu oikein joten on äärimmäisen epätodennäköistä, että kaksi eri salasanaa tuottaisi saman tiivisteen.
Lopuksi vielä lyhyt yhteenveto
Oikeaoppinen tapa tallentaa salasana sisäänkirjautumista varten on käyttää erityista salasanatiivistealgoritmia. Näille algoritmeille löytyy valmiit kirjastot yleisesti käytetyille kielille ja tuki niille löytyy valmiina useimmista frameworkeista. Esimerkiksi Djangon auth moduli käyttää oletuksena PBKDF2 algoritmia. Mikäli selvätekstisiä salasanoja tarvitaan sovelluksen sisällä, kannattaa salasanat kryptata ennen tietokantaan säilömistä.