Sinds november beheer ik niet alleen de site arnecoomans.nl, maar ook de server waar de site op draait. Dat houdt in dat ik naast WordPress-gebruiker nu ook beheerder ben van het onderliggende systeem. En dus ook voor de beveiliging van het geheel. Al snel werd ik geconfronteerd met keuzes in het systeem die onherroepelijk gevolgen zal hebben voor het gemak waarmee WordPress gebruikt wordt. Ik ontdekte hoe makkelijker WordPress gebruikt kan worden, hoe groter de beveiligingsrisico’s. Alles wat ik makkelijk als WordPress-beheerder kan, kan het systeem ook mogelijk als het gehackt wordt.

De uitdaging

Als WordPress-beheerder zijn de belangen anders. Dan moet het snel, efficiënt en zonder onnodige formulieren en vertragingen werken.

Als serverbeheerder wil je WordPress zo veel mogelijk onmogelijk maken iets zelfstandig uit te voeren op de server. Want de kans dat het mis gaat is groot.

Waarom is dat zo moeilijk?

Twee kapteins op één schip?

Op mijn server heb ik een eigen gebruiker: arne. Met deze gebruiker kan ik inloggen via ssh en sftp en kan ik alle web-content bewerken. Dat is wel zo veilig en er kan minder mis gaan.

Maar mijn websites (specifieker gezegd php) draait onder systeemgebruiker www-data. Om te zorgen dat mijn website toch getoond kan worden delen ze een groep. Php mag dus alle bestanden in mijn document-root lezen en gebruiken.

Uploads

Hierdoor loopt WordPress al snel vast bij het plaatsen van een nieuw artikel. Bij het toevoegen aan de broodnodige illustratie van een lap tekst wil ik via de admin-pagina van WordPress een afbeelding toevoegen. Deze wordt via http naar php gestuurd, waar gebruiker www-data gaat schrijven in de map die van arne is. En daar ontbreken de rechten toe.

Dus de eerste concessie wordt al snel gedaan. De map /wp-content/uploads wordt schrijfbaar voor alle leden van de groep. Hierdoor mag WordPress zelf bestanden toevoegen aan de website en is de applicatie verantwoordelijkheid voor de beveiliging hiervan.

$ chmod 775 /wp-data/uploads

Dit zorgt er voor dat www-data zich enkel mag uitleven in de specifieke uploads-map. Pas als je bestanden wilt verwijderen via sftp of ssh zal je tegen beperkingen aanlopen. Alle uploads zijn van www-data.

Uitvoeren scripts in /uploads

Hierdoor ontstaat wel het risico dat er een script wordt geplaatst tussen de uploads. Zo kan een geregistreerde gebruiker bijvoorbeeld een php-script uploaden waarmee alle data binnen de site te lezen is. En te overschrijven.

Het gevolg van het aanpassen van de rechten op de map uploads is dus dat er maatregelen moeten worden getroffen dat er geen onveilige bestanden kunnen worden uitgevoerd. De eerste controle hiervan ligt binnen WordPress-applicatie. Maar als server-beheerder wil ik de omgeving indekken tegen fouten of onvoorzichtigheid.

Er zijn dan grofweg twee mogelijkheden.

Toegang tot .php bestanden ontzeggen

Via de Nginx serverconfiguratie kan ik makkelijk de toegang tot alle bestanden die eindigen op .php ontzeggen. Dat houdt in dat er geen php script kan worden aangeroepen welke malafide code kan uitvoeren. Dit doe ik met de server-configuratie:

In /etc/nginx/sites-available/server

location ~* /(?:uploads|files)/.*\.php$ {
 deny all;
 }

Deze tip heb ik van de wordpress-codex. Hierdoor zal deze link leiden tot een “access denied”-pagina. Afhankelijk van welke mogelijkheden mijn server biedt zal ik dit moeten uitbreiden om ook andere bestandsformaten uit te sluiten.

Toegang beperken tot .png, .jpg, .gif en .pdf.

Een strenger alternatief is om bovenstaande beperking te herschrijven naar een whitelist. Dat zou inhouden dat enkel afbeeldingen en een pdf als attachment benaderd zou mogen worden. Ik denk dat de config er ongeveer zo uit zo moeten zien:

In /etc/nginx/sites-available/server

location ~* /(?:uploads|files)/.*\.(?:jpg|jpeg|gif|png|pdf))$ {
 deny all;
 }

Dit zorgt er voor dat de server een stuk minder toelaat dan de applicatie en kan dus snel tot onverwacht gedrag leiden. Ook introduceert het extra onderhoud, want zodra er meer mogelijk moet worden is de serverbeheerder vereist.

Binnen nginx moet in de serverconfiguratie expliciet worden aangegeven dat een .php bestand naar de php processor gestuurd moet worden. Zo lang er geen andere scripts worden uitgevoerd is het beperken van toegang tot .php waarschijnlijk voldoende.

Ook de omweg afsluiten

Er blijft dan nog één manier waarop php scripts alsnog kunnen worden uitgevoerd: door het php script als directory op te nemen. In plaats van /wp-content/uploads/secure.php wordt dan /wp-content/uploads/secure.php/test.jpg aangeroepen. De volgende toevoeging in php.ini moet dat voorkomen:

cgi.fix_pathinfo = 1"

Lees meer uit dossier WordPress
Dit artikel verscheen ook op True.nl/blog