Inloggen voor je eigen platform: passkeys en inloglinks
Voor een klein platform is inloggen zonder wachtwoord meestal veiliger en makkelijker: een inloglink per mail voor de eerste keer, en daarna een passkey. Bij een passkey blijft het geheime deel van een sleutelpaar op het toestel van je gebruiker, zodat er in je database niets staat waarmee een inbreker kan inloggen. Verzin zelf geen beveiliging, maar laat Claude bestaande standaarden gebruiken en geef hem alle eisen vooraf mee.
Voor een klein platform is de beste manier van inloggen er een zonder wachtwoord. De eerste keer krijgt iemand een link in zijn mail. Daarna logt hij in met een passkey: een digitale sleutel op zijn telefoon of laptop, die hij ontgrendelt zoals hij dat toestel ontgrendelt, bijvoorbeeld met een vingerafdruk of pincode. Voor je gebruikers is dat prettiger dan nog een wachtwoord onthouden. Voor jou is het veiliger, omdat er in je database geen wachtwoorden staan waar een inbreker iets mee kan. Het lastige deel is niet het idee, maar de uitvoering. Claude kan dit goed bouwen, als je hem vertelt waar hij op moet letten.
Waarom wachtwoorden een last zijn
Een wachtwoord dat jij bewaart, is een risico dat jij draagt. Mensen gebruiken hun wachtwoorden op meer plekken, dus als jouw database ooit uitlekt, kan een inbreker daarmee misschien ook elders binnenkomen, tot in iemands mailbox. Wie toch met wachtwoorden werkt, slaat ze nooit leesbaar op. Je bewaart een hash: een berekende code waaruit het wachtwoord niet terug te halen valt, gemaakt met een methode die bewust veel rekenwerk kost, zodat raden traag gaat. OWASP, een open project van beveiligingsspecialisten, adviseert daarvoor Argon2id in zijn richtlijn over het opslaan van wachtwoorden.
Daarmee ben je er nog niet. Er moet een herstelroute komen voor wie zijn wachtwoord kwijt is, en een rem op iemand die duizenden pogingen doet. Allemaal werk om iets te beschermen wat je liever helemaal niet zou hebben.
De inloglink, met vier voorwaarden
Bij een inloglink typt iemand alleen zijn mailadres. Je platform stuurt een link, en wie daarop klikt, is binnen. Wie bij de mailbox kan, kan dus inloggen, en een mailbox is meestal stevig beveiligd. Toch is het minder simpel dan het klinkt. Deze vier voorwaarden geef je Claude mee:
- Een link is kort geldig, bijvoorbeeld vijftien minuten, en werkt één keer.
- Je platform geeft na het invullen altijd dezelfde reactie, ook bij een adres dat het niet kent. Zo kan niemand aftasten wie er klant bij je is.
- Er geldt een maximum aan aanvragen, per IP-adres en per mailadres. Een IP-adres is het internetadres van de computer die de aanvraag doet.
- Een klik op de link logt nog niet in. De link opent eerst een pagina met een knop. Sommige mailprogramma’s en virusscanners openen links in een mail namelijk automatisch om ze na te kijken, en dan zou je link al opgebruikt zijn voordat je klant erop klikt.
De eerste twee voorwaarden noemt OWASP ook in zijn richtlijn voor herstelpagina’s: codes horen eenmalig te zijn en te vervallen, en bekende en onbekende accounts krijgen dezelfde reactie.
Er zit één afhankelijkheid aan: de mail moet vlot aankomen. Een mail die je rechtstreeks vanaf een pas gehuurde server verstuurt, wordt vaak als spam gezien of helemaal niet afgeleverd. In Een contactformulier dat echt aankomt lees je hoe een maildienst dat oplost.
Passkeys in gewone woorden
Een passkey bestaat uit twee sleutels die bij elkaar horen: een geheime en een openbare. Wie weleens met een SSH-sleutel op een server heeft ingelogd, kent het principe (zie Inloggen met een sleutel in plaats van een wachtwoord). Je platform krijgt alleen de openbare sleutel. De geheime blijft op het toestel van de gebruiker, of in de wachtwoordmanager van bijvoorbeeld Apple of Google, die hem beveiligd naar de andere toestellen van die gebruiker kopieert. Bij het inloggen laat het toestel zien dat het de geheime sleutel bezit, zonder hem prijs te geven.
Daar zitten twee voordelen aan. Een inbreker die je database steelt, vindt alleen openbare sleutels, en daar kan hij niet mee inloggen. Daarnaast hoort een passkey bij jouw domein. Browsers en besturingssystemen gebruiken hem alleen voor de site waarvoor hij is aangemaakt, dus een nagemaakte inlogpagina krijgt niets. Daarom noemt de FIDO Alliance, de organisatie achter de standaard, passkeys bestand tegen phishing: het lokken naar een valse site om inloggegevens buit te maken. Een heldere uitleg, ook voor wie zelf bouwt, staat op passkeys.dev.
Google spreekt in het Nederlands van een toegangssleutel. Niet iedereen kent het al, en op een nieuwe telefoon heeft iemand zijn passkey soms nog niet. Daarom werk je met allebei: de link per mail om binnen te komen als het nodig is, en de passkey als gewone manier van inloggen. Is een telefoon zoek en komt de passkey niet vanzelf mee naar het nieuwe toestel, dan vraagt de gebruiker een link aan en maakt hij een nieuwe passkey.
Na het inloggen
Is iemand binnen, dan krijgt zijn browser van je server een cookie met een lange, onvoorspelbare code. Die code heet de sessie. Hij gaat met elke pagina mee, en zo herkent je programma de bezoeker. Wie de code onderschept, kan zich als die bezoeker voordoen, dus de cookie moet afgeschermd zijn. In de richtlijn van OWASP over sessies staan de instellingen daarvoor. HttpOnly zorgt dat scripts op de pagina de cookie niet kunnen uitlezen, en Secure dat hij alleen over een versleutelde verbinding gaat. Met SameSite beperk je dat andere sites hem meesturen. Geef sessies verder een vervaldatum, en laat uitloggen de sessie ook op je server ongeldig maken.
Weten wie iemand is, is nog niet hetzelfde als weten wat hij mag. Je programma moet bij elk verzoek ook nagaan of deze persoon dit specifieke ding mag zien of doen. Een klant die zijn bestelling ziet op /bestelling/14 en in de adresbalk 15 typt, hoort een foutmelding te krijgen en niet de bestelling van iemand anders. Die controle ontbreekt nogal eens. Meer daarover lees je in Waarom apps die met AI gebouwd zijn zo vaak lekken.
Wat je niet zelf verzint
Versleuteling en inlogcodes zijn geen terrein om te improviseren. Passkeys werken via een vaste standaard, WebAuthn, en daarvoor bestaan bibliotheken die al door veel anderen zijn gebruikt en getest. Vraag Claude welke bibliotheek hij kiest en of die nog actief wordt onderhouden.
Een voorbeeld. Pieter is keramist en verkoopt een online cursus glazuren. Cursisten die betaald hebben, krijgen toegang tot alle lessen; anderen kunnen alleen de eerste les bekijken. In zijn opdracht aan Claude beschrijft hij eerst de opzet: geen wachtwoorden, een link per mail voor de eerste keer en daarna een passkey. Dan volgen de vier voorwaarden voor de link en de instellingen van de cookie. Hij vraagt ook om bij elke les na te gaan of de cursist betaald heeft. Als laatste zin vraagt hij Claude om nog niets te bouwen en eerst een plan te tonen, met de bibliotheken die hij wil gebruiken. Pieter legt dat plan naast zijn lijstje voorwaarden en geeft pas akkoord als alles erin staat.
Twee valkuilen kun je meteen in zo’n opdracht noemen. Een passkey werkt alleen over een versleutelde verbinding (https) en op je eigen domein. Test hem dus pas als je platform op zijn definitieve adres met slotje staat. Verder draait je programma meestal achter een webserver zoals nginx, die de bezoekers doorgeeft. Zorg dan dat je programma het echte IP-adres van elke bezoeker te zien krijgt. Anders lijkt elke aanvraag van dezelfde bezoeker te komen, en blokkeert je maximum aan aanvragen iedereen tegelijk. Wat er verder bij een eigen platform komt kijken, lees je in Zelf een app of platform bouwen zonder programmeerervaring.
Krijgt jouw platform een inlog, zet je voorwaarden dan op papier voordat Claude begint, en vergelijk zijn plan daarmee. Probeer na het bouwen zelf een link die al gebruikt is en een link die te oud is. Maak ook twee testaccounts en kijk of het ene account iets van het andere kan zien. Lukt dat niet, dan zit je voordeur goed dicht.
Foto bovenaan: iam hogir via Pexels