Autopsie van de tweedags-tool: “Ben ik ge-Odido’d?” (NL)

Autopsie van de tweedags-tool: “Ben ik ge-Odido’d?” (NL)

In dit artikel bundel ik de twee eerdere blogposts met alle informatie over de odidod-tool: hoe het is ontstaan, hoe het werkte, welke overwegingen en besluiten ik had genomen en uiteindelijk hoe en waarom het is afgesloten. (web-archief van de tool en blogpost 1, 2)

Het begon met vragen die onbeantwoord bleven in de uren na het eerste deel van de Odido-datalek: welke gegevens hebben ze precies van mij, en zijn die inmiddels al gelekt? Begrijpelijke zorgen, maar op dat moment was er nog geen duidelijk antwoord. Verwijzen naar "Have I Been Pwned" of "CheckJeHack" had toen ook weinig zin, omdat zij de data nog niet hadden verwerkt.

Daarom had ik diezelfde dag nog een tool online gezet voor vrienden, familie, (oud-)collega’s, kennissen en andere (oud-)klanten die zich zorgen maakten over hun gegevens. Inmiddels is die weer offline gehaald, omdat "Have I Been Pwned" de lekken bijhoudt en de tool daardoor al snel overbodig werd. Gelukkig maar, want eerlijk gezegd maakte het me ook best een beetje nerveus. Let me explain:

1) De tool

Laat ik beginnen met een uitleg van hoe de tool voor de eindgebruiker werkte. Heel simpel: er waren twee modi; één om te zoeken op e-mailadres en één om te zoeken op woonadres.

Dit omdat na analyse door experts ook bleek dat er echt wel wat records in de data stonden zonder e-mailadres. Dat brak dan ook meteen mijn eerste plan, waarbij het e-mailadres eerst geverifieerd moest worden met een one-time password. Ik kon moeilijk ook een fysieke postflow opzetten om thuisadressen te gaan verifiëren…

Dus met de nodige twijfel heb ik, gezien het feit dat Have I Been Pwned ook geen voorverificatie afdwingt, toch besloten hun model aan te houden. De adresfunctie heb ik na lang overwegen alsnog er in gelaten, juist omdat de groep klanten zonder e-mailadres in mijn ogen vaak het meest kwetsbaar zijn voor misbruik door criminelen.

Nadat de gebruiker de zoekopdracht had uitgevoerd, kreeg deze een resultaat te zien, met of zonder aangetroffen gegevens:

goed nieuws!
Oh oh..

En dan kom ik op dun ijs terecht, waarbij mijn eerdere voorbereidingen het lastig maakten. In plaats van alleen een “Oei”-scherm te tonen, zoals bij Have I Been Pwned, had ik dit gedeelte nog ingericht vanuit het idee dat vooraf geverifieerde e-mailverificatie er voor stond. Daarbij kon je zien welke velden gevuld waren en welke niet.

Hier heb ik het langst over getwijfeld. De data zelf zou nooit inzichtelijk zijn voor de gebruiker, want die was er simpelweg niet, maar je kon wel zien dát er iets stond. Allemaal met het idee dat de gebruiker zichzelf geverifieerd had. Dat is natuurlijk extreem gevoelig, en er is een reden dat HIBP (Have I Been Pwned, vanaf nu afgekort omdat ik het anders zo vaak moet typen) dat dan ook niet doet…

Ik weet niet of ik dat een volgende keer weer zo zou doen, al hoop ik eerlijk gezegd dat ik dit nooit meer wil bouwen. Wel ben ik benieuwd of er een expert is die dit leest en hier een duidelijk antwoord op heeft. Als dat zo is, dan hoop ik dat je contact met me opneemt. Ben erg nieuwschierig...

Tot slot stond onderaan de resultatenpagina een knop om de ruwe data uit te lezen van de backend-server:

De gegevens die je in de screenshots ziet, zijn van de gebruiker “test@test.com”. Deze arme klant heeft inmiddels 590+ databreaches overleefd en komt in bijna elke gebruikersdatabase wel terug. Ik begin me toch een beetje zorgen te maken over deze beste man…

Oh ja, en de enige reden dat de frontend er zo netjes uitziet, is omdat ik, (iemand met vrij weinig gevoel voor design, zie deze blogsite) een LLM heb gevraagd om mijn HTML-frontend wat op te fleuren met Bootstrap… En met die deur in huis vallen we meteen bij de…

2) Technische toelichting

Daar ging de tweede blogpost over, en die kan ik nu eindelijk aanvullen met wat meer technische details:

2.1) De ETL Toolset

De reden/ een van de redenen is/ dat ik de site zo snel kon opzetten, was omdat ik veel programmadelen kon hergebruiken die ik eerder had geschreven, waaronder de custom ETL-toolset die de “Ben ik ge-Odido’d”-dataset moest opbouwen.

Projecten folder loopt een beetje uit de hand

Het doel was om de gelekte data te verwerken zonder deze daadwerkelijk te downloaden. Dat klinkt misschien wat vaag, maar ging zo: de gelekte data wordt via een webserver met publiek IP-adres beschikbaar gesteld door de hackers. Dat maakte dit (helaas) een stuk makkelijker. De ETL las de gecomprimeerde data als een datastroom in het geheugen, pakte deze daar uit en doorzocht die vervolgens met behulp van vooraf gedefinieerde formules op basis van regex-patronen en keyvalues.

Omdat ik dit toen in Rust had geschreven en deze programmeertaal uitstekend geschikt is voor zware of complexe geheugenmanipulaties, ging dat erg rap. Daarnaast controleerde de ETL semi-automatisch of er nieuwe gecomprimeerde databestanden beschikbaar waren d.m.v. mijn bash wrapper script.

Bij het aantreffen van een regex-patroon of een key-value werd deze gehasht met een secret en in de index geplaatst. Daarna werd de hele record in de dataset gezet met de gegevens als “key":"value”, waarbij de key behouden blijft en de string value altijd wordt leeggemaakt en vervangen door een aanduiding zoals “data” of “empty”. De enige uitzondering hierop zijn booleans; die worden niet als persoonsgegevens beschouwd en blijven dus intact.

Een voorbeeld van een simpele if/elseif/else checker die ik er tussen propte

Met standaard deduplicatie en adressen die in een componentopstelling werden gezet voordat deze gehasht werden.

Tot slot werd de hele dataset plus index versleuteld, zodat de gehashte gegevens niet te lezen zijn zonder de "masterkey". En zelfs met die "masterkey" kun je zonder de hashkey nog steeds vrij weinig. Een aardige deterministische hashing-setup.

2.2) De Serving stack

De backend heb ik grotendeels opgebouwd uit mijn bestaande vaakgebruikte modulaire-serve-stack in GoLang, inclusief een vrij eenvoudige maar inmiddels proven API-structje. Met wat implementatie werk kon ik de dataset weer ontsleutelen en een snel opbouwen door de index te laten verwerken en een lookup-table door middel van offsets te genereren, om ook het resourcegebruik zo laag mogelijk te houden, en vooral flexibel te blijven. Alle functies moesten hot kunnen draaien tijdens het serven voor het geval er later meer data toegevoegd zou worden.

Ik had heel graag alle source-code willen delen, maar het meeste er van is elders nog in gebruik...

2.3) De Timeline (bonus)

De timeline is ook wel grappig om vast te leggen: De dag vóór het eerste lek (25-02-2026) was eigenlijk al duidelijk dat Odido niet zou gaan betalen, en had ik al wat kleine voorbereidingen getroffen voor het geval ik dit projectje echt wilde doorzetten. In deze fase was alles nog volledig conceptueel, maar wel concreet genoeg om alvast een plan van aanpak te maken.

Donderdagochtend (26-02-2026) kwam inderdaad het nieuws dat de eerste miljoen regels waren gelekt. Al snel bleek dat het het welbekende Salesforce-schema betrof, met aardig wat custom velden. Ook werd voor mij meteen duidelijk dat ik mijn plan moest aanpassen, zoals ik hierboven beschreef. Dus na een werksessie van 11:55 tot 18:10 had ik een stack die deed wat hij moest doen. En door mijn extended-test-checklist heen kwam (zegt verder niks he). Daarna de knoop doorgehakt om live te gaan en heb ik om 16:22 de domeinen aangeschaft.

Nog vóór 19:00 stond het publiekelijk live en had ik het gedeeld met de eerste mensen die mij, als ICT-kennis, al hadden gevraagd hoe ze konden uitzoeken of hun data al gelekt was als (oud-)klant.

Op 27-02-2026 heb ik nog wel met de ETL toolset het tweede datalek verwerkt, maar toen was al duidelijk dat HIBP in sync was. In de nacht van 28-02-2026 (om 01:38) heb ik uiteindelijk de boel afgesloten, zoals je hierboven en hieronder kunt lezen. En daarmee ook de custom dataset vernietigd.

3) Gestelde vragen

Komt uit het oude blogpost:


Kort samengevat:

  • Er worden geen e-mailadressen, fysieke adressen of andere leesbare gegevens opgeslagen
  • We kunnen wél matches uitvoeren op e-mailadressen en adressen door middel van deterministische hashing met een sleutel
  • Oorspronkelijke veldinhoud is niet aanwezig, alleen een gehashte “indicator”

Q: Is het veilig?
A:
Ja, zo veilig mogelijk. We doen ons best, maar als je kijkt naar Odido waren je gegevens daar veilig? Het doel van de tool is om (oud-)klanten inzicht te geven in welke gegevens mogelijk zijn gelekt. Snelheid speelt daarbij een belangrijke rol, omdat partijen die misbruik willen maken van gelekte data vaak snel handelen.

Q: Hoe is dit zo snel gebouwd?
A:
Het grootste deel van de code hadden we al beschikbaar (ik werk altijd modulair), met name de backend-API, appender, en de ETL-transformatielaag. Op forums kon ik al zien hoe het schema eruitzag toen de eerste gegevens lekten, waardoor ik mijn bestaande tooling hierop kon aanpassen zonder de data zelf te hoeven bekijken.

Frontend-ontwikkeling is niet mijn sterkste kant, dat is op deze site waarschijnlijk ook wel te zien, daarom is de frontend volledig opgebouwd met behulp van generatieve AI (LLM).

Q: Hoe bedoel je tijdelijk?
A:
Heel simpel: zodra CheckjeHack en HaveIBeenPwned volledig up-to-date zijn en de schade geleden is haal ik de tool offline, en blijft er een technische autopsie over. Op dat moment is de site dan overbodig geworden.

Q: Welke informatie verwerk je?
A:
Vrijwel geen. Je opdracht via de frontend wordt direct naar de backendserver gestuurd. Er worden geen sessies aangemaakt en er wordt na verwerking niets opgeslagen.

Het enige wat in het geheugen draait, zijn counters voor het afdwingen van API-regels, zoals rate limiting. Alle logging en analytics zijn voor deze dienst uitgeschakeld. Dat is vanuit privacy-oogpunt een bewuste keuze, al betekent het wel dat ik niet kan zien hoeveel mensen de tool gebruiken.

Op hardware- of virtualisatieniveau kan ik alleen het totale aantal bytes aan inkomend en uitgaand verkeer meten.


4) Afsluiter

Toen na dag twee al snel bleek dat HIBP de datalekken net zo snel verwerkte als “Ben ik ge-Odido’d?”, werd duidelijk dat deze tool overbodig begon te worden. Ondanks dat we net iets meer indicatoren hadden en meer informatie, bracht dat voor mij ook meer zorgen met zich mee. Na overleg met wat oud-collega’s, experts en zelfs een raadsman in opleiding was het inderdaad tijd om de schaar erdoor te halen.

Uiteraard heeft Checkjehack nog geen update:

28-02-26

Voor iedereen die me bedankte dat ze geen gebruik hoefden te maken van een Amerikaanse dienst of server: sorry

Dus zodoende: is “Ben ik ge-Odido’d?” twee volle dagen trots tot dienst geweest.

En als kers op de taart mocht mijn ongerelateerde post toch blijven staan op Tweakers, waar ik na lange tijd weer een account had aangemaakt om door een door mij bijna vergeten favoriete topic te scrollen:


5) En nu?

Tja, bijna iedereen heeft inmiddels zijn plasje over de Odido-hack gedaan en er een mening over. De één vond dat er betaald moest worden, de ander juist niet. Als je leest wie deze hackers zijn en wat ze in het verleden hebben uitgespookt, snap ik in dit geval wel dat er niet is betaald. Het zijn niet bepaald strak in het pak zittende partijen met een trackrecord waarvan je zegt: dit was een dure les, maar we zijn door het oog van de naald gekropen. Ik moet hier wel aan toevoegen dat er tot nu toe nog geen data is gelekt door deze groep waarvan de garantie is afgekocht.

Als we naar de feiten kijken, heeft Odido veel steken laten vallen, zeker nu er langzaam in de media naar buiten komt dat er eerder al een hoop waarschuwingen waren. Maar helaas is dat wel hoe dit soort dingen vaak gaan, maar ook zullen blijven gaan. En ik vind ook dat Odido d'r klanten erg in het donker laat.

Wat ik ook opvallend vind, is dat er relatief weinig aandacht is voor het toch wel grote aantal oud-klanten dat betrokken is, waarvan velen al ruim buiten de door Odido aangegeven bewaartermijn van persoonsgegevens vielen. Die gegevens zijn in mijn optiek ook compleet onnodig gelekt.


Ik ben zelf een groot voorstander van checklists, zoals in de luchtvaart: een piloot doet elke dag meerdere keren hetzelfde, maar werkt toch telkens dezelfde checklists af. En zelfs dan kan er nog wel eens sprake zijn van een vroegtijdige ongeplande “vliegtuigontmanteling”…
Dus ja, wat is de volgende?

"Een complete "gevibecode" fullstack SaaS identification oplossing voor de nieuwe leeftijdsrestricties op websites 😎"

Meer, of minder pasportnummers?!

To be continued...

Proost,