Ga naar inhoud
Van bouwen naar borgen: een week zonder nieuwe functies

Van bouwen naar borgen: een week zonder nieuwe functies

· Bert Altena

Een week zonder nieuwe functies: een module die elk bestand van het platform bijhoudt met drie controles, vier beveiligingsrondes en alle geheimen de webmap uit.

Er komt in elk project een moment waarop doorbouwen niet meer het verstandigste is. Bij het boekingsplatform waar ik deze zomer aan werk kwam dat moment eind juli. Zes modules stonden er, het systeem draaide, en ik merkte dat ik bij elke wijziging langer zat te zoeken naar wat er nog meer aan hing.

Dus heb ik een week lang niets nieuws gebouwd. In plaats daarvan: een module die bijhoudt hoe het met de code zelf staat, vier beveiligingsrondes, en alles wat geheim moet blijven uit de webmap. Dit is wat dat opleverde.

Elk bestand krijgt drie controles

Het grootste stuk is een module die ik integriteitbeheer noem. Die inventariseert het hele project als een bestandsverkenner: pad, grootte, wijzigingsdatum, rechten, een hash van de inhoud en of het bestand in versiebeheer staat.

Per bestand houdt hij drie controles apart bij. Is dit dode code? Zit er verouderde of te omslachtige code in? En is het veilig? Pas als alle drie zijn afgetekend wordt het bestand groen. Verandert de inhoud daarna, dan klopt de hash niet meer, valt de aftekening af en moeten de drie stappen opnieuw.

Dat laatste is het hele idee. Een controle zegt alleen iets over de versie die je toen hebt gelezen. Inbraakdetectie werkt al dertig jaar zo: je keurt een toestand bewust goed en krijgt bericht zodra die toestand verandert. Ik heb dat model overgenomen en er de kwaliteitscontroles bij gezet, want die verouderen precies zo hard.

De scanner draait negen regelpakketten: blootstelling, rechten en herkomst, sleutels, achterdeuren, injectie en XSS, toegangscontrole, verouderde PHP, de huisregels van het project, en dode code. Verwijderen kan alleen via een knop die eerst een kopie in een archief buiten de webmap zet.

Het echte werk zat in de valse meldingen

De eerste ronde over de echte code gaf 3.578 meldingen, waarvan 48 met hoog risico. Onbruikbaar. Bij die aantallen kijkt niemand meer naar de lijst, en dan is een scanner erger dan geen scanner.

Twee dagen bijstellen bracht het terug naar 518 meldingen, zonder dat er een echte bevinding wegviel. De enige die met hoog risico overbleef was terecht, en die is meteen gedicht. Een proefbestand met opzettelijke fouten wordt onverminderd volledig gevonden.

Wat daar zoal misging, is leerzaam. Een patroon dat op `require` zocht greep ook het woord `required`, en meldde daarmee vijftien onschuldige regels als code-uitvoering op afstand. Een regel die naar `${var}` zocht sloeg aan op JavaScript in een template, waar diezelfde notatie iets heel anders betekent. En achttien handlers werden gemeld voor een ontbrekende beveiliging die al centraal geregeld was, een laag hoger.

De les die ik hieruit meeneem: een regel met een voorvoegsel en een vrij staartje is levensgevaarlijk. Draai elke nieuwe regel eerst over het hele project en kijk wat hij vangt voordat je hem aanzet.

Vier rondes langs de voordeur

Naast de scanner ben ik zelf vier keer het systeem doorgelopen, elke keer met een andere bril.

De eerste ronde ging over beheeracties die geen eigen controle hadden. De tweede over de publieke voorkant. De derde vond rauwe SQL die via een boekingsveld naar binnen kon, en een factuur-eindpunt dat zonder controle open stond. De vierde vond twee plekken waar bedragen zonder authenticatie op te vragen waren, plus drie dingen die ik in ronde drie zelf kapot had gemaakt.

Die laatste zin staat er bewust. Bij dit soort werk introduceer je nieuwe fouten, en de enige remedie is opnieuw kijken. Er kwam snelheidsbegrenzing op het inloggen bij, plus een tokencontrole op schrijfacties via GET. Ruim dertig beheeracties kregen een rolcontrole; tot dan toe leunden die alleen op "is ingelogd".

Sleutels de deur uit

Het platform gebruikte een enkele sleutel voor te veel dingen tegelijk: sessies, links in e-mails, wachtwoordherstel. Dat is comfortabel tot de dag dat er eentje uitlekt.

Die sleutel is nu gesplitst. Er is een aparte, lange sleutel voor het ondertekenen van links, met HMAC en een timingveilige vergelijking. De omzetting ging in drie stappen, met terugval, zodat bestaande links van klanten bleven werken terwijl er niets meer op de oude sleutel geschreven werd. Toen de laatste gebruiker om was, kon de oude weg.

In dezelfde week zijn alle oude wachtwoorden in blokken omgezet naar bcrypt, voor klanten, beheerders, eigenaren en beoordelaars. En de historische kaartgegevens zijn opgeruimd: velden weggehaald uit de formulieren, ontsleutel-queries eruit, oude waarden leeggemaakt. Gegevens die je niet bewaart, kunnen ook niet uitlekken.

Alles wat geheim is naar buiten

De configuratie met de databankgegevens, de logbestanden, de reservekopieën, de migraties en de documentatie stonden allemaal in de webmap. Met de juiste URL en een beetje geduld zijn zulke bestanden vaak gewoon op te halen.

Ze staan nu buiten de webmap, met een terugval zodat een installatie die nog niet verhuisd is blijft werken. De uitrol spiegelt de migraties naar de nieuwe plek en ruimt de oude op. Logs roteren en hebben een bewaartermijn. De `.git`-map is dicht.

Het aardige is dat integriteitbeheer nu zelf controleert of die verhuizing gelukt is. Op het servertabblad staat of de mappen echt buiten de installatie liggen en of er nog logbestanden in de webmap staan. Zonder SSH, gewoon op het scherm.

Ook nog: vijf seconden gevonden

Tussendoor heb ik een meting ingebouwd die trage verzoeken vastlegt in plaats van erover te gissen. Dat leverde direct twee dingen op.

De Wijzigingen-pagina deed 6.489 queries en doet er nu 3. En ergens zat een consequente vertraging van vijf seconden die niemand kon plaatsen. Het bleek de automatische klasse-lader te zijn, die telkens zocht naar een bestand dat niet bestond, en pas na alle mogelijke paden opgaf.

Dat soort dingen vind je niet door beter na te denken. Je vindt ze door te meten.

Wat ik hiervan meeneem

Een controle heeft een houdbaarheidsdatum. Zonder hash weet je niet of je oordeel nog over de huidige inhoud gaat. Met een hash weet je het wel, en dat is het verschil tussen een lijstje en een systeem.

Een scanner met veel ruis is erger dan geen scanner. Je went aan rode regels, en dan zie je de echte niet meer. De tijd die in het bijstellen van regels gaat zitten, is de investering die de tool bruikbaar maakt.

Onderhoud is werk, geen restpost. Een week zonder nieuwe functies voelt onproductief, tot je terugkijkt en ziet wat er dicht is gegaan.

Lees ook

Loopt er bij jou een systeem waarvan niemand meer precies weet wat erin zit? Dat is normaler dan je denkt, en het is op te lossen. Plan een vrijblijvend gesprek. Ik kijk eerst waar de risico's zitten voordat ik iets aanraad.

Bert

Chat met ons