Han loggade in med sitt konto och landade på någon annans

En användare loggade in på en tjänst jag driver, med sitt eget konto, och landade på någon annans.

Inte en felaktig namnvisning. Han såg den andra personens sida, den andras uppgifter, den andras projekt. Rapporten kom som ett meddelande på en minut: ”loggar in med mitt konto men hamnar hos någon annan”.

Det tog tio minuter att hitta orsaken, tre till att åtgärda den, och resten av dagen att sluta må illa. Det här är vad som hade hänt.

Två register över samma människor

Tjänsten hade vuxit fram i två omgångar och släpade på en historisk skavank: användarna fanns i två separata databaser.

Inloggningsflödet skrev till den ena. De inloggade sidorna läste från den andra. Kopplingen dem emellan var ett löpnummer — och ingen hade någonsin sagt åt de två databaserna att dela numrering.

Så länge samma personer skapades i samma ordning i båda register råkade numren stämma överens. Systemet fungerade perfekt i månader, av ren tur.

Ögonblicket då turen tog slut

En ny användare registrerade sig. Hon hamnade i det ena registret men inte i det andra. Från och med den sekunden var numreringen förskjuten med ett steg.

Nästa person som loggade in fick en session märkt med sitt nummer ur det ena registret. Sidorna slog upp det numret i det andra registret — och fick fram en helt annan människa.

Det som gör det obehagligt är att varje enskilt steg var korrekt. Inloggningen verifierade rätt person mot rätt leverantör. Sessionen skapades korrekt. Uppslaget gjordes korrekt. Felet fanns bara i antagandet att två nummer från två oberoende källor betydde samma sak.

Ingen data läckte i praktiken — de berörda kontona var i stort sett tomma. Men det var tur, inte konstruktion, och tur är inte en säkerhetsmodell.

Åtgärden, och en stunds förnedring

Fixen var att sluta använda ett internt löpnummer som brygga mellan systemen och i stället knyta sessionen till en identitet som betyder samma sak i båda — och sedan ogiltigförklara samtliga aktiva sessioner, eftersom vilken som helst av dem kunde peka fel.

Två minuter efter att rättningen gått live kraschade inloggningen med ett nytt fel: en variabel som bytt namn i städningen och som jag missat på ett ställe. Ytterligare en rättning, ytterligare en driftsättning, och sedan fungerade flödet.

Den detaljen tar jag med av en anledning: bråttom-rättningar har en egen felfrekvens. Jag stod inför valet att låta ett identitetsfel ligga kvar i tio minuter till för att hinna granska ordentligt, eller att stänga hålet direkt och riskera följdfel. Jag valde det senare och skulle välja det igen — men man ska veta att man valt.

Så vet du att du inte har samma fel

Räkna dina användarregister. Är svaret fler än ett har du det här felet latent, oavsett hur säker du är på att de hålls i synk.

Fråga vad sessionen egentligen pekar på. Ett internt löpnummer är ingen identitet — det är en position i en tabell. Identiteten ska vara något som betyder samma sak överallt.

Testa med två konton samtidigt, i två webbläsare, efter att en tredje användare skapats. Det är precis det scenariot som avslöjar förskjutningen, och precis det man aldrig testar.

Vad jag tar med mig

Det farligaste felet är inte det som kraschar. Det är det som fungerar länge, av en slump, och slutar fungera vid en händelse som ingen kopplar till felet — här: att en ny användare registrerade sig.

Och det som gäller alla system jag byggt det här året: identitet tål inte två sanningar. Inventarium tål det inte, nätverkskonfiguration tål det inte, och användare allra minst — för där heter konsekvensen inte avdrift utan att någon ser någon annans uppgifter.

Skrivet av Daniel Azzarri · Om · Alla inlägg