Om een veilige applicatie te bouwen, worden vaak twee of meer authenticatie mechanismen gecombineerd (Two Factor Authentication). Vaak is dit voor een webapplicatie een combinatie van authenticatie met gebruikersnaam en wachtwoord plus een token gegenereerd vanaf een mobiele telefoon. Dit is natuurlijk niet het meest gebruiksvriendelijke proces. Mobiele applicaties hebben het voordeel gebruik te kunnen maken van out-of-the-box fingerprint authenticatie of gezichtsherkenning, maar dit kunnen we niet gebruiken voor webapplicaties. In dit artikel introduceer ik de concepten achter keystroke dynamics.

Allereerst een disclaimer: Authenticatie is een complex probleem, met veel risico’s als het verkeerd in een applicatie geïmplementeerd wordt. Dit artikel is alleen bedoeld om de concepten achter keystroke dynamics te introduceren, niet om een productie klaar product te tonen. Probeer dit dus niet zelf te implementeren, maar maak gebruik van een aanbieder van software in dit veld (bijvoorbeeld het bedrijf TypingDNA).

Er zijn drie categorieën van gebruikersauthenticatie. De eerste categorie is gebaseerd op authenticatie door middel van iets wat de gebruiker weet (Something you know). Dit kan bijvoorbeeld een gebruikersnaam- en wachtwoordcombinatie zijn. De tweede categorie is gebaseerd op authenticatie door middel van iets wat de gebruiker heeft, zoals bijvoorbeeld een mobiele telefoon (Something you have). Door middel van een token opgeslagen op de telefoon kan de gebruiker zich vervolgens identificeren bij de applicatie. De derde categorie is authenticatie gebaseerd op een biometrische of psychologische eigenschap van de gebruiker, zoals bijvoorbeeld een vingerafdruk (Something you are).

Keystroke Dynamics

Keystroke dynamics is gebaseerd op het feit dat elke gebruiker een unieke manier heeft om te typen op een computer, net zoals iedereen een uniek handschrift heeft. Ritme, aanslag, pauzes tussen de aanslagen, enz. zijn samengenomen tot een patroon. Op basis daarvan is de gebruiker te identificeren. Aan de hand van deze patronen kan een persoonsgebonden classifier gecreëerd worden. Dit is een model die de gebruikers kan onderscheiden aan de hand van hun type patronen. Hoe accurater deze classifier, hoe beter we in staat zijn de identiteit van de gebruiker te verifiëren. Elke nieuwe inlogpoging van de gebruiker wordt gevalideerd tegen deze classifier.

Om een classifier te creëren die de gebruikers kan identificeren, moeten we eerst de typpatronen van de gebruikers verzamelen. De gebruiker wordt tijdens het registreren gevraagd om een bepaalde zin te herhalen om deze features te kunnen verzamelen. Het succesvol herhalen van deze zin noemen we een sample. In de literatuur staat beschreven dat minder dan 6 samples niet aangeraden wordt, aangezien dit de precisie van onze classifier zou beïnvloeden1. De lengte van deze zin heeft ook invloed op de classifier: in de literatuur worden samples korter dan 10 tekens niet aangeraden2.

De samples worden gebruikt om de typpatronen van een gebruiker te verzamelen. In de literatuur zijn verschillende features relevant bevonden voor het identificeren van een patroon.

 

  • Dwell Time: De tijd tussen het aanslaan van toets A het loslaten van toets A.
  • Key Press Latency: De tijd tussen het aanslaan van toets A en het aanslaan van toets B.
  • Key Release Latency: De tijd tussen het loslaten van toets A en het loslaten van toets B. Dit kan een negatieve waarde zijn als de gebruiker toets B eerst loslaat.
  • Flight Time: De tijd tussen het loslaten van toets A en het aanslaan van toets B. Dit kan een negatieve waarde zijn als de gebruiker toets B aanslaat voordat de gebruiker toets A loslaat.
  • Digraph: De tijd tussen het aanslaan van toets A en het loslaten van toets B. Dit kan gegeneraliseerd worden naar features van het type N-graph, waar N de hoeveelheid toetsen aangeeft. Maar over het algemeen is N > 3 niet relevant.

Op basis van deze features kan een template worden gecreëerd, dat de typpatronen van de gebruikers representeert. Deze template bevat een aggregatie van de features van de tijdens registratie verzamelde gebruikers-typpatronen. Aan de hand van deze template trainen we een classifier. De classifier wordt uiteindelijk gebruikt om de gebruiker te identificeren. Drie verschillende categorieën van classifiers worden toegepast in dit veld:

  • Statistische classifiers: Deze classifiers onderscheiden gebruikers van elkaar d.m.v. een maat van statistische afstand, zoals bijvoorbeeld de euclidische afstand, de afstand tussen twee punten in een n-dimensionale ruimte. Als n=2 dan is dit simpelweg de stelling van Pythagoras. Denk hier bijvoorbeeld aan de K-means en Nearest Neighbours algorithmes.
  • Fuzzy Logic: Fuzzy logic creëert een regel gebaseerde classifier, die i.p.v. 0/1 boolean logica, het resultaat van een regel tussen 0 en 1 definieert.
  • Artificiële neurale netwerken: Neurale netwerken zijn in staat non-lineaire beslissingsgrenzen te maken in waarmee we onze gebruikers kunnen onderscheiden.

Om de classifiers te evalueren en de accuraatheid van de classifier in te schatten, wordt gebruik gemaakt van twee maatstaven. De false acceptance rate (FAR) geeft aan welk percentage van gebruikers foutief geïdentificeerd werd als een andere gebruiker door de classifier. De false rejection rate (FRR) geeft aan welk percentage gebruikers niet geïdentificeerd werd. Zoals je je misschien wel kan voorstellen, is de FAR hier de belangrijkste maatstaf: we willen namelijk niet dat kwaadaardige gebruikers zich gemakkelijk kunnen voordoen als een ander.

Eenmalig een classifier trainen is niet genoeg. Gebruikers zullen over tijd hun typpatronen veranderen. Iemand die voor het eerst een toetsenbord gebruikt zal een jaar later heel anders typen. Een gebruiker die een nieuw toetsenbord aanschaft, zal ook zijn patronen veranderen. We moeten dus continu onze classifiers opnieuw trainen en evalueren.

Web-based Authenticatie systeem

Maar hoe implementeren we dit in een webapplicatie? Daarvoor beginnen we met het verzamelen van de typpatronen in de browser. De moderne web API triggert een ‘KeyboardEvent’ om een gebruikersinteractie met het toetsenbord te beschrijven. Er zijn drie soorten events, namelijk het keyup, keypress- en het keydown event. De keydown en keyup events zijn vrij eenvoudig: ze beschrijven respectievelijk het indrukken en loslaten van een toets. Het keypress event is een kleine variatie op het keydown event: deze vuurt alleen op normale lettertoetsen (en sluit dus toetsen zoals Alt en Shift uit).

Voor het meten van een gebruikers-typpatroon is het belangrijk dat we accuraat de tijd tussen twee toetsaanslagen kunnen meten. Hiervoor is de ‘Performance’ interface beschikbaar in browsers. Volgens de specificaties zou ‘performance.now()’ een timestamp met een precisie van microseconden terug moeten geven, maar vanwege bepaalde cyberaanvallen (zoals Spectre) is de precisie afgerond op milliseconden. Sommige browsers ondersteunen ook anti-fingerprinting-maatregelen, vanuit privacy overwegingen. Dit betekent dat de timestamp wordt afgerond op 100 milliseconden. Om accuraat een classifier te trainen, hebben we tijdmetingen met hoge precisie nodig. Een lagere precisie kan ertoe leiden dat gebruikers onterecht als een andere gebruiker worden gezien. Helaas is hier geen alternatief voor beschikbaar in browsers. Dit kan een limiterende factor zijn in de adoptie van keystroke dynamics als primair authenticatie mechanisme.

 

In de snippet hierboven zie je een TypeScript voorbeeld van hoe we deze keyboard events kunnen verzamelen. De applicatie registreert de tijd van interactie met ‘performance.now()’ en haalt de relevante informatie uit het ‘KeyboardEvent’. Zodra het sample compleet is (de gebruiker heeft succesvol de opdracht zin uitgetypt), wordt het naar het backend-systeem gestuurd.

Feature extractie

Aan de hand van de verzamelde keyboard-events kunnen we de relevante features voor onze classifier extraheren en daarmee het template van de gebruiker creëren. Dit betekent dat we voor een sample de dwell time, flight time, etc. moeten berekenen.

 

Hierboven staat het resulterende JSON object wat naar de backend gestuurd wordt. Dit object bevat een sample van de gebruiker, met daarin een lijst van KeyboardEvents. Om hier de relevante features uit te extraheren, moeten we onze events aggregeren per sample per gebruiker (sessie). De complexiteit ligt hem hier in het feit dat geen garantie is dat het event voor het aanslaan van de q-toets wordt gevolgd door het loslaten van de q-toets. De volgende reeks geeft bijvoorbeeld het probleem aan ((q, keydown), (w, keydown), (w, keyup), (q, keydown)). Een simpele sliding-window operatie om de features te berekenen over de lijst van events, waarbij een aggregatie wordt uitgevoerd over twee events tegelijkertijd (zoals bij de SQL LAG operator), volstaat dus niet. Daarom is het belangrijk om eerst de lijst van events te reduceren tot een lijst van tuples keydown- en keyup-tijden per key. Dit staat ons dan vervolgens toe om de correcte aggregatie uit te voeren.

 

Hier transformeren we de lijst van keystroke events naar een lijst van tuples. Vervolgens kunnen we deze lijst aggregeren om onze features te berekenen.

 

Om bijvoorbeeld de dwell time te berekenen, kunnen we simpelweg de keydown-tijd van de keyup-tijd aftrekken. De complete set van features is op een soortgelijke manier te berekenen. Aan de hand van deze aggregatie van de features creëren we het template van de gebruiker.

De juiste classifier kiezen

De volgende stap is om een ​​classifier te trainen aan de hand van het template, zodat we nieuwe inlogpogingen kunnen valideren. Zoals eerder vermeld, bestaan verschillende benaderingen om een ​​classifier te maken. De vraag is: “Wat is de ideale classifier voor een web-based authenticatie systeem”?

We willen een oplossing waarbij het systeem bij een registratie van nieuwe gebruikers snel een classifier kan trainen, anders is het registratieproces ongebruiksvriendelijk en haken mensen af. Neurale netwerken gebruiken alle data beschikbaar om een classifier te trainen door middel van beslissingsgrenzen tussen de verschillende datapunten. Als we een neuraal netwerk gebruiken, die de data van alle gebruikers nodig heeft om daar de beslissingsgrenzen tussen te bepalen, betekent dat dat de trainingstijd (lineair) langer wordt hoe meer gebruikers er zijn. We willen niet dat onze gebruikers moeten wachten totdat een classifier getraind is.

In plaats daarvan is de beste manier om een algoritme, zoals Nearest Neighbours, te gebruiken. K-Nearest Neighbours (k-NN) zijn in staat snel een set aan templates te doorzoeken naar de dichtstbijzijnde liggende punten. De afstand tussen punten wordt bepaald aan de hand van de euclidische afstand van alle features. In andere woorden: hoe meer het typpatroon van een inlogpoging afwijkt van het template van een gebruiker, des te groter de euclidische afstand zal zijn.

Als het template dat is gevonden door het algoritme overeenkomt met de template van de gebruiker die op dit moment inlogt, dan weten we dat de correcte gebruiker aan het inloggen is. Als het niet overeenkomt, dan blokkeren we de inlogpoging. Hier zijn een aantal heuristieken bij nodig. Als er weinig gebruikers zijn, zal een punt sneller nabij zijn dan als we veel gebruikers in ons systeem hebben. Er is dus een maximale afstand die we kunnen accepteren, een threshold.

 

In het figuur hierboven zie je een (simplistisch) voorbeeld van een k-NN algoritme aan de hand van twee features. De rode punten in dit figuur zijn het template van de gebruiker: de aggregatie van de typpatronen van de gebruiker, zoals verzameld tijdens de registratie en latere inlogpogingen. De cirkel representeert de threshold van deze classifier. Aan de hand van de template wordt deze waarde bepaald. Het blauwe punt is een nieuwe inlogpoging, die in dit geval geblokkeerd zal worden, aangezien deze buiten de threshold valt.

De complexiteit in het trainen van een Nearest Neighbour classifier voor keystroke dynamics ligt in het bepalen van de FAR en de FRR. De FAR is het percentage false positives, onterechte succesvolle authenticaties. Maar dit kunnen we pas meten als we meetpunten hebben waar een gebruiker foutief geïdentificeerd werd. Dit is gemakkelijk te realiseren in een gecontroleerde studie, maar in een webbased authenticatiesysteem kunnen we niet wachten op foutieve identificaties. Dat is wat we juist proberen te voorkomen!

In plaats daarvan moeten we een benadering vinden voor de FAR. Dit kan bijvoorbeeld door in Nearest Neighbours voor elke nieuwe registratie de templates van de dichtstbijzijnde gebruikers te vergelijken met de template van de nieuwe registrant. Als deze geaccepteerd worden door de classifier, dan weten we dat deze te tolerant is. Met deze approximatie van de FAR kunnen we ook de threshold afstand optimaliseren. Hierin ligt wel een probleem voor het gebruik van keystroke dynamics als een authenticatie mechanisme. Voor een goede approximatie van de FAR zijn we afhankelijk van de hoeveelheid gebruikers in ons systeem! Maar er zijn al succesvolle studies gedaan met groepen zo klein als 12 gebruikers3.

TypingDNA

Een library die gebruik maakt van keystroke dynamics is TypingDNA4. TypingDNA bestaat uit twee delen: een JavaScript client en een set aan backend API’s (zie het figuur hieronder). Door het importeren van het ‘typingdna.js’-script worden in de achtergrond de typpatronen van de gebruiker verzameld. Deze kunnen dan meegestuurd worden naar jouw applicatie, waarna met de TypingDNA API’s de typpatronen van de gebruiker geregistreerd kunnen worden of geverifieerd kan worden of de typpatronen matchen met de verwachte gebruiker.

 

De toekomst

In dit artikel heb ik jullie hopelijk een beeld gegeven wat keystroke dynamics is, en hoe het toegepast kan worden in authenticatie. Hoewel ik een voorbeeld heb gegeven van keystroke dynamics als tweede factor voor de authenticatie van gebruikers, zijn er nog veel meer use cases. Recentelijk zijn wetenschappelijke artikelen verschenen waarin keystroke dynamics werden gebruikt om de emotie van een gebruiker te bepalen. Een boze gebruiker typt anders dan een ontspannen gebruiker. Wat ook een interessante ontwikkeling in dit veld is, is het gebruik van keystroke dynamics om te bepalen of een gebruiker liegt of niet. In het wetenschappelijke artikel werd een accuraatheid van 75% (!) bereikt. Verzekeraars en banken zouden graag een dergelijk systeem willen hebben. Er zijn dus nog genoeg mogelijkheden in dit veld. Ik ben benieuwd wat de toekomst ons brengt.