TOONbeeld

een blog over conceptontwikkeling > ontwerp > techniek

onder redactie van
SchelvisOntwerp KoetsierEngineering
ontwerp en
implementatie

, door Marten Koetsier

onderwerpen:

Gehakt voor de hacker: over wachtwoorden in databases

Regelmatig is het in het nieuws dat er een database met wachtwoordinformatie van een website is gestolen. Met deze wachtwoorden kunnen hackers inloggen en bijvoorbeeld namens de slachtoffers geld uitgeven. Is het wel veilig om wachtwoorden in een database op te slaan? Hoe veilig is die opslag? Lees in deze blog hoe het werkt.

Met enige regelmaat meldt het nieuws dat er een database met wachtwoorden is gestolen. Onlangs nog weer van eBay. Hieruit blijkt ten eerste dat het kennelijk mogelijk is dat die databases op straat kunnen komen te liggen. Hoewel systeembeheerders meestal hun best doen om dat te voorkomen, is dat risico kennelijk niet te onderschatten. Maar bovendien blijkt hieruit dat wachtwoorden kennelijk nog steeds vaak zodanig in databases zijn opgeslagen, dat het mogelijk is om ze in te zien. Bij eBay zit dat redelijk goed, maar in andere gevallen is accountinformatie openlijk leesbaar, of anderszins te achterhalen, zoals bij Realworks in januari vorig jaar. Dit laatste kan voorkomen worden door middel van goede password hashing. In dit artikel leg ik uit hoe dat werkt en waarom we het moeten gebruiken.

De meest eenvoudige manier om met behulp van een database een wachtwoordbeveiliging voor een website te maken, is als volgt. Je legt een tabel aan in de database die de gebruikersnaam en het wachtwoord voor elk account bevat. Het script kan vervolgens bij een poging tot inloggen die tabel raadplegen en uitzoeken of de juiste gegevens zijn verstrekt.

Deze oplossing heeft echter een belangrijk probleem: de wachtwoorden zijn zichtbaar voor iedereen met toegang tot de database. In principe zijn dat de systeembeheerder(s), het script en eventueel hackers. En zijn die te vertrouwen?

Systeembeheerders zijn meestal wel te vertrouwen omdat ze doorgaans geen belang hebben bij de gegevens. Meestal. Edward Snowden bleek achteraf toch bijbedoelingen gehad te hebben, hoewel dat niet over wachtwoorden ging. Of het script te vertrouwen is, hangt in belangrijke mate af van de programmeur(s). Door het gebruik van moderne technieken en goed testen is het best mogelijk om een script veilig te maken. Het belangrijkste gevaar zit 'm in SQL injection. Met deze techniek kan een kwaadwillende gebruiker invoervelden op een website (web-formulieren) misbruiken door specifieke code in te voeren. Het gelinkte Wikipedia-artikel laat goed zien hoe dit in z'n werk gaat. Hoewel de genoemde techniek om dit te voorkomen wat verouderd is, is het goed mogelijk om SQL injection tegen te gaan.

En dan de hackers die er toch telkens weer in slagen om zich toegang tot de database te verschaffen. Veel hackers doen dit om beveiligingslekken op te sporen en de beheerders de kans te geven de problemen op te lossen voordat er iets mis gaat. Maar soms zijn kwaadwillende hackers ze voor en dan gaat het mis.

Hachee

Gelukkig is het mogelijk om een wachtwoord versleuteld op te slaan in de database. Hierdoor heb je niks aan de wachtwoorden wanneer je ze hebt gestolen. Dit versleutelen gebeurt op een manier die maar één kant op werkt: hashing. Dit woord is te vertalen met hachee of mengelmoes. Het werkwoord to hash betekent zoveel als klutsen of hakken, bijvoorbeeld zoals in het woord rundergehakt. Met hashing wordt een tekst, in ons geval het wachtwoord, dus flink gehusseld. Zo erg, dat niet meer te herleiden is wat de oorspronkelijke tekst was. Net als dat je aan een gehaktbal niet meer kan zien dat het ooit vlees was en al helemaal niet welk stuk vlees.

In de computer gebeurt dit met een wiskundige bewerking die gebruik maakt van hoe letters in de digitale wereld worden opgeslagen: in bits en bytes. Al vroeg in de geschiedenis van computers is afgesproken hoe dit gecodeerd wordt. Elke letter wordt gerepresenteerd door een getal. Zo is ooit afgesproken dat de hoofdletter A de waarde 65 heeft. Zonder al te veel op de kunst van het binaire stelsel in te gaan, is dit voor een computer het getal 0x01000001 (waarbij "0x" een veelgebruikte manier is om aan te geven dat een binair getal bedoeld wordt en niet een "gewoon" decimaal getal). Met die nullen en enen gaat de computer schuiven en ruilen. De getalswaarden van de letters uit het wachtwoord worden bij elkaar opgeteld, van elkaar afgetrokken of anderszins gecombineerd. Er wordt flink gehakt en gemengd en uiteindelijk is de uitkomst van deze berekening een getal met altijd een vaste lengte: de hash. Een belangrijk verschil met een slager is dat een hash-functie deterministisch is: een gelijke invoer geeft ook altijd dezelfde hash.

Er zijn verschillende hash-functies, zoals MD5, de SHA-familie en Whirlpool. Belangrijke verschillen tussen de diverse hash-functies zijn hoe de functie precies werkt. Ofwel: hoe er gehakt wordt.

Bij alle hash-functies wordt een hoeveelheid informatie telkens zo versleuteld dat er een getal uitkomt dat altijd dezelfde lengte heeft. Zelfs als de oorspronkelijke tekst duizenden pagina's groot is. Uit het feit dat de uitkomst altijd dezelfde lengte heeft, blijkt al dat er bij hashing altijd informatie verloren gaat. Dat is belangrijk, want mede daardoor kan je nooit meer de oorspronkelijke tekst herleiden. En dat is precies de bedoeling. Toch? Hoe kan je dan controleren of iemand het juiste wachtwoord opgeeft? Eenvoudig: door ook die invoer te hashen (met dezelfde hashfunctie natuurlijk) en de twee uitkomsten met elkaar te vergelijken. De uitkomst zou namelijk wel weer telkens hetzelfde getal moeten zijn.

Een goede hash-functie moet voldoen aan een drietal belangrijke eigenschappen. Ten eerste moet het moeilijk zijn om een tekst te verzinnen die een vooraf gedefinieerde uitkomst heeft. Anders is het eenvoudig om bij een gevonden hash een passend wachtwoord te vinden. Dit hoeft niet eens het oorspronkelijke wachtwoord te zijn: als de hash maar overeenkomt. Ten tweede moet het moeilijk zijn om een tekst te wijzigen zonder dat de hash verandert. Anders kan het voorkomen dat een wachtwoord ondanks een type-fout toch toegang verschaft tot de website. En ten derde moet het moeilijk zijn om twee teksten te vinden die dezelfde hash uitkomst opleveren. Deze eis lijkt een beetje op de eerste, maar hier gaat het erom dat een goede distributie van alle mogelijke hashes de kans kleiner maakt dat verschillende wachtwoorden dezelfde hash opleveren. Als aan een van deze eisen niet wordt voldaan, is de kans groot dat een hacker met alleen een hash alsnog makkelijk toegang kan krijgen tot de website.

Dan is het belangrijk om te definiëren wat "moeilijk" is. Doorgaans wordt hier in de praktijk mee bedoeld dat het ondoenlijk is voor een aanvaller om een oplossing te vinden binnen de tijd dat het systeem actueel is. Dit hangt dus ook af van de toepassing. Als het langer dan honderd jaar duurt om een wachtwoord te achterhalen, is je wachtwoord dus je hele leven lang veilig. Ook houdt je daarbij rekening met de te verwachten vooruitgang in de techniek. Een belangrijke factor hierin is de lengte van de hash. Bij een hash van 128 bit (zoals bij MD5) heb je al 3,4×1038 mogelijkheden, meer dan 340 triljoen maal zoveel als het geschatte aantal sterren in het "observeerbare universum". Voordat je die allemaal geprobeerd hebt…

Kortom, we hebben nu een database met daarin alleen maar hashes. De aanvaller (hacker) kan dus geen wachtwoorden meer zien. Maar dit is helaas niet genoeg.

Vooraf berekenen

Een wachtwoord is meestal vrij kort, ergens tussen de 6 en 9 karakters. Als we er vanuit gaan dat een wachtwoord doorgaans bestaat uit letters (hoofdletters en kleine letters), cijfers en de leestekens die op een regulier toetsenbord voorkomen, kunnen we gaan rekenen met 95 verschillende karakters. Voor een wachtwoord met 6 karakters, betekent dat dat er zo'n 7×1011 verschillende mogelijke wachtwoorden zijn. Dat is iets meer dan het aantal sterren in het Melkwegstelsel.

Maar helaas, mensen gebruiken maar een fractie van die mogelijkheden. We zijn geneigd om vooral letters te gebruiken, waarvan weinig hoofdletters, en zo nu en dan een getal. Het schijnt dat bijna de helft van de mensen alleen maar kleine letters gebruikt. Dan zijn er nog maar 3×108 mogelijkheden. Dat lijkt veel, maar die wachtwoorden kan je allemaal opslaan in een bestand van 1,8 GB. En als je dan alleen "bestaande" woorden meeneemt (en ja, die komen het meest voor in wachtwoorden), wordt het nog minder. Op een gegeven moment wordt het mogelijk om van al deze wachtwoorden vooraf al de hashes te berekenen en deze vast in een tabel op te slaan. Dat betekent dat als je beslag weet te leggen op een database met wachtwoord-hashes, je de hashes eenvoudigweg gaat vergelijken met je tabel. Je zult zo niet alle wachtwoorden kraken omdat niet iedereen zo'n makkelijk wachtwoord gebruikt, maar vaak is één account al genoeg…

Zout en peper in de hachee

Een voor de hand liggende oplossing is dat niet alleen het wachtwoord gehasht wordt. Hierboven had ik het over de drie belangrijke eigenschappen van hash-functies. De tweede daarvan komt hier van pas: zodra er ook maar één letter verandert aan het wachtwoord, is de hash anders en is die niet meer zonder meer terug te vinden in een tabel. En hier geldt hetzelfde als voor wachtwoorden: hoe willekeuriger en langer de toevoeging, hoe beter. En elk account dient z'n eigen toevoeging te hebben, anders is het voor de hacker eenvoudig om een tabel te maken waarbij hij al rekening houdt met die toevoeging.

Deze truc wordt breed toegepast en de letters die toegevoegd worden aan het wachtwoord voorafgaand aan het hashen heet salt. Net als dat zout in hachee de smaak verandert, verandert salt de uitkomst van de hash. Maar het is niet duidelijk of de term hiervan afgeleid is. Er worden nog wat andere mogelijkheden geopperd, zoals een relatie met de vermeende (en onbevestigde) truc van de Romeinen om de waterbronnen in Carthage zout te maken om de mensen daar (de vijand) het leven moeilijk te maken, net als dat een salted hash moeilijker te kraken is. Of dat het een referentie is naar het Engelse to salt away, spreektaal voor het stiekem iets bewaren (met name geld). Ook is salting a mine een methode om een mijn van interessante waar te voorzien om 'm duurder te kunnen verkopen (een vorm van bedrog).

De salt wordt normaal gesproken opgeslagen samen met de overige account-informatie. Dat lijkt gek, maar het doel van de salt is het tegengaan van het gebruik van tabellen. Het script moet natuurlijk wel kunnen verifiëren of het juiste wachtwoord is ingevoerd. En daar is de salt bij nodig. Omdat elk account z'n eigen salt heeft, moet het script deze kunnen opzoeken en de database is daarvoor nu eenmaal de aangewezen plaats.

Door toevoeging van een salt wordt het (heel veel) moeilijker om alle wachtwoorden in een database te kraken. Maar het kraken van één wachtwoord (met dus een bekende salt) is niet per se veel moeilijker. Daarom kan er nog een truc worden toegepast: het toevoegen van een salt die uniek is voor een applicatie en die buiten de database wordt opgeslagen, bijvoorbeeld in een initialisatie-bestand in het script. Om deze salt te onderscheiden van de gewone salt, wordt deze ook wel pepper genoemd. Mocht de database (of bijvoorbeeld een backup daarvan) in verkeerde handen vallen, dan is het kraken van de wachtwoorden alsnog schier onmogelijk zonder de peper. En de kans dat een hacker óók het script kan inzien is veel kleiner dan dat hij de hand weet te leggen op een database.

Maak gehakt van de hacker

Kort samengevat is het aan te bevelen om wachtwoorden niet open en bloot op te slaan in een database. In plaats daarvan wordt er een salt en mogelijk ook een pepper toegevoegd aan het wachtwoord en deze combinatie wordt vervolgens gehasht. De salt en de hash worden opgeslagen in de database, de eventuele pepper wordt elders opgeslagen, bijvoorbeeld in een initialisatiebestand van de applicatie. Bij een login-poging worden de (bekende) salt (uit de database) en pepper (uit het script) gecombineerd met het opgegeven wachtwoord en opnieuw gehashed. De hash moet overeenkomen met die in de database om de login succesvol te laten zijn.

share

Deel dit artikel op LinkedIn LinkedIn zodat ook de mensen in uw netwerk ervan kunnen profiteren.

Wilt u deze blog ergens anders delen, gebruikt u dan de permanente link:
http://toonbeeld.info/2014/11/02/gehakt-voor-de-hacker-over-wachtwoorden-in-databases.

0 reacties (lees ook de kleine lettertjes)
Reageer ook!