Vorige week zijn we gestart met het migreren van hostingpakketten op cluster 1 naar een nieuw storageplatform. Aangezien de manier waarop de storage aan onze webservers aangeboden wordt niet verandert (NFS) zou dit voor de sites die erop draaien transparant moeten zijn: zij zouden geen verschil moeten zien. Helaas zijn er natuurlijk altijd zaken die de NFS-specificatie niet afdekt, en die wij niet hebben voorzien. En klanten weten die zere plekjes altijd feilloos te vinden …

Vanochtend werden we gebeld door een partner die melde dat hij last had van de migratie: zijn sites werkten niet meer goed. Het bleek dat hij periodiek code genereerde aan de hand van broncode in andere bestanden. Deze bestanden werden ingelezen met behulp van readdir. Daarbij was de volgorde waarin de bestanden door readdir gelezen werden van essentieel belang voor de gegenereerde code.

 

Readdir doet zelf niets anders dan aan het onderliggende filessysteem vragen wat de inhoud van een directory is. Het filesysteem bepaalt wat de volgorde van die files is. Dat betekent dat op webservers die op Windows draaien NTFS de volgorde bepaalt, op webservers die op Linux draaien de volgorde bepaald wordt door Ext3, XFS of andere Linux filesystemen. En bij hosters die aan clusterhosting doen zou de volgorde dan bepaald worden door NFS, omdat de storage van het netwerk komt.

 

Helaas wordt die volgorde niet door NFS bepaald, maar door het filesysteem van de NFS-server (of fileserver). Deze fileserver is nu net hetgeen wij aan het vervangen zijn: onze NS20 is aan het eind van zijn economische levensduur, en we zijn aan het overstappen naar ZFS.

 

Om de verschillen in de volgorde van de filesystemen van de NS20 en ZFS te zien, gebruiken we het volgende PHP-scriptje dat gewoon op één van onze webservers draait:

Het resultaat hiervan is het volgende. De linkerkolom is het resultaat op de NS20, rechts is ZFS, de nieuwe omgeving.

Bij beide systemen is er geen logische volgorde te ontdekken. Stiekum is die er bij de NS20 wel: het is de volgorde waarin de bestanden aangemaakt zijn. Bij ZFS is er echt geen logische volgorde: ZFS gebruikt een hashingalgoritme om bestanden in directories bij te houden, dus de volgorde wordt bepaald door dat algoritme.

Duidelijk is in elk geval: het is onverstandig om ervan uit te gaan dat de volgorde van bestanden in een directory altijd hetzelfde is!

 

Hoe kun je dit dan oplossen? De eenvoudigste oplossing is scandir(). Dit is een broertje van readdir, maar is eenvoudiger in gebruik en belangrijker: scandir sorteert het resultaat! Als we bovenstaande test opnieuw uitvoeren met onderstaand script, waarin we scandir gebruiken, is het resultaat zoals verwacht.

 

De volgorde is hetzelfde, en de code is simpeler. Win-win :).

En mooiere en veiligere oplossing zou zijn om een whitelist bij de houden van bestanden die geinclude moeten worden. Het is nu natuurlijk betrekkelijk eenvoudig om code aan de site toe te voegen, als je schrijfrechten hebt gekregen voor deze site. Een simpele FTP-hack, een verouderd component in je CMS of een andere programmeerfout geeft dan volledige toegang.

 

Conclusie: vertrouw niet de volgorde waarin je de bestanden van een filesystem terugkrijgt, ook niet als dat tijdens het testen in de gewenste volgorde gebeurt. Er kan van alles gebeuren waardoor die volgorde wijzigt. Zoals ook op php.net staat: “the order in which directory entries are returned [..] is system-dependent.”

Scan je eigen Magento shop op veiligheidslekken