Zo’n tien jaar geleden heb ik een artikel geschreven over de veiligheid van WordPress. En destijds was men het er wereldwijd wel over eens, dat WordPress op dat moment het meest veilige CMS was, wat er is. Vandaag de dat is dat echter niet meer het geval.
Wat mankeert er aan? Hoe veilig is WordPress nu echt en wat kan je doen om de veiligheid te verhogen? Ik zal je alvast verklappen, dat het in dit artikel niet over ‘security plugins’ gaat. We kijken er wat serieuzer naar.
Hoe veilig is WordPress ? Cijfertjes die je niet blij zullen maken
Sucuri heeft een overzicht gemaakt van verschillende CMS-en en de aantallen infecties met malware. Hier bleek dat in 2019 (de meest recente cijfers, 2020 zal waarschijnlijk ergens in de loop van dit jaar komen) WordPress de grote leider was met 94,23% van alle gevallen.
Ofwel, als we alle geïnfecteerde CMS-en naast elkaar zetten, dan is WordPress hierin wel de grote leider. Op de tweede plaatst stond Joomla! met 2,49%.
Daar staat overigens ook tegenover -zoals je in hetzelfde rapport op pagina 8 kan lezen- dat WordPress de motor is achter 35.2% van alle websites en 62% van alle CMS-en. Er zijn dus behoorlijk wat WordPress websites om te hacken. Maar bijna 95% is toch wel heel veel.
Hoe komt dat?
Allereerst natuurlijk omdat het natuurlijk veel meer opbrengt om een WordPress website te hacken, dan bijvoorbeeld een Typo3 website. De laatste heeft een marktaandeel van 0,5%. Wanneer we deze marktaandelen en het aantal gehackte sites met elkaar vergelijken, blijkt in verhouding het aantal gehackte websites Typo3 niet eens zoveel lager te liggen, dan de aantallen gehackte WordPress websites.
Geen updates
In het geval van hacks was 56% van alle CMS-en (dus niet alleen de WordPress sites) ‘out of date’, oftewel, geen regelmatige updates. Nu kan ik mij bij een CMS als Typo3 daar wel iets bij voorstellen. Tenminste, indien het updaten nog steeds zo’n nachtmerrie is als enkele jaren geleden, maar met een WordPress website is er eigenlijk geen goede reden te bedenken om het updaten na te laten!
Maar er is nog een aantal andere goede redenen aan te geven, waarom een WordPress website eigenlijk heel kwetsbaar is. En de eerste reden geldt eigenlijk niet alleen voor WordPress, maar voor ieder CMS wat op het lijstje van Sucuri staat.
Eenmaal binnen… ben je binnen
Stel je twee verschillende situaties voor. Twee verschillende mensen die allebei een kostbare diamant bezitten. De eerste persoon heeft die diamant in een doosje met een grote sticker ‘afblijven’ in het midden van de huiskamer staan.
De tweede persoon heeft die diamant in een kluis van een afgesloten kantoor staan.
Beide mensen hebben veilige sloten op de buitendeur en ’s nachts gaan de rolluiken voor de ramen.
Wie van de twee denk je dat het makkelijkste slachtoffer voor een ramkraak wordt?
Het probleem met (bijna) alle zogenaamde ‘LAMP’ stack toepassingen (Linux / Apache / MySQL / PHP) is namelijk, dat de beveiligingsgegevens opgeslagen zijn binnen een deel van het file systeem wat toegankelijk is vanaf het internet. Het bestand ‘wp-config.php’, waar bijvoorbeeld de inloggegevens voor je database instaan, is vrijelijk toegankelijk vanaf het Internet. Vraag ik het bestand op, dan zal ik niets zien, omdat Apache en PHP dit bestand niet als ’tekst’, maar als programmacode zien, maar er is een aantal manieren waarop ik toch de inhoud van zo’n bestand kan lezen.
En heb ik eenmaal toegang tot je database, dan kan ik die toegang weer gebruiken, om toegang de krijgen als gebruiker tot WordPress. Ik kan hier sowieso twee manieren bedenken, waarop ik dit vrij makkelijk kan doen.
PHP laten crashen
Er zijn verschillende ’trucs’ mogelijk om PHP te laten crashen. PHP is de programmeertaal waar WordPress in geschreven is en vraag je je af ‘hoe veilig is WordPress’, dan is het goed om je ook af te vragen hoe recent de door jou gebruikte PHP versie is.
PHP code kan er bijvoorbeeld als volgt uitzien :
<h1>
<?php
echo "Hello World";
?>
</h1>
Zelfs wanneer je nog nooit van je leven hebt geprogrammeerd, kan je je hier waarschijnlijk wel iets bij voorstellen. Zou ik deze code in een bestand plaatsen en dit bestand de extensie ‘.php’ geven, dan gaat Apache, de webserver, ervan uit, dat dit bestand geïnterpreteerd moet worden door PHP. En in plaats van de inhoud van dit bestand direct naar jou toe te sturen, wordt het ‘bekeken’ en aangepast door PHP.
Waar <?php begint en ?> eindigt, daar wordt de code door PHP geïnterpreteerd. En de code zegt heel simpel : “Hello world”.
Omdat er in HTML een h1 tag omheen staat, zal ‘Hello World’ in een behoorlijk groot lettertype getoond worden.
Maar wat nu, wanneer nu door een bug in PHP die ‘vertaling’ door PHP ineens uitvalt? Dan is één van de mogelijke resultaten, dat Apache denkt* een door PHP behandeld bestand ontvangen te hebben, maar in werkelijkheid is de inhoud nog steeds hetzelfde. Dat is niet zo belangrijk als de inhoud alleen maar ‘Hello World’ is, maar wat, wanneer in dit bestand je wachtwoorden staan opgeslagen, zoals in het wp-config.php bestand?
In het verleden is het een aantal keren gebeurd, dat door PHP onverwachte dingen te laten doen, door een fout van de programmeurs, PHP kon crashen. In een sterk vereenvoudigd voorbeeld (zo simpel was het nooit), je weet waarschijnlijk wel dat ‘delen door nul’ niet kan. Maar stel nu, dat op een bepaald punt in een berekening de maker van een PHP module is vergeten hier een controle in te bouwen.
En stel nu, dat iemand dat ontdekt zou hebben, maar ook ontdekte, dat deze handeling leidt tot het crashen van PHP… en PHP dus geen gegevens meer interpreteert, maar direct laat zien?
Het enige wat ik zou hoeven te doen, is veel servers te benaderen met deze truc. En een aantal servers zal dan inderdaad ineens PHP code gaan tonen.
Nu worden dit soort fouten meestal heel snel ontdekt, en in de meeste gevallen al voor de software daadwerkelijk in productie gaat. Maar stel, dat jouw hoster niet altijd bijtijds de software update. Dan loop je toch een aardig risico.
PHP omzeilen
Normaal gesproken worden alleen bestanden met een extensie ‘.php’ door de PHP interpreter bekeken. Er zijn echter programma editors, die de extensie van je bestand aanpassen. Wanneer je vroeger met WordPerfect hebt gewerkt, dan ken je vast de ‘bak’ bestanden nogwel.
Een aantal programma editors doet eigenlijk net zoiets. Sommige editors doen het structureel (ze behouden de oude versie, voor je ging aanpassen), andere doen het alleen tijdens het editen zelf (en ruimen het op zodra de editor wordt verlaten. Maar ook bij de laatste groep editors kan het mis gaan. Want wat als die editor crasht?
Bij mij op de server houd ik een 404 logging bij. Ik kan zo zien, naar welke bestanden, die niet voorkomen bij mij op de server, toch gevraagd wordt. Dat doe ik niet, omdat ik graag grote, lange bestanden verzamel, maar vooral omdat in deze bestanden belangrijke informatie terug te vinden is.
Een deel van deze ‘vragen’ komt namelijk van hackers. En het is altijd goed te zien, naar welke bestanden deze zoeken, want dat zijn vaak bestanden met bekende exploits. Zoekt iemand bijvoorbeeld naar /wp-content/plugins/willekeurigepluginnaam/index.php, dan is er een aardige kans dat ‘willekeurigepluginnaam’ een plugin met een zeker risico is. En dan is het goed om dit in de gaten te houden.
Wat ik ook heel veel zie, is dat er gezocht wordt naar configuratiebestanden met ‘vreemde’ extensies.
Het bestand wp-config.php bevat, zoals aangegeven, cruciale informatie. Gelukkig onttrekt PHP dat bestand aan ‘vreemde ogen’, omdat het bestand met .php eindigt.
Wat ik echter in mijn 404 logs zie, is dat er ook regelmatig gezocht wordt naar wp-config.old, wp-config.php~ (sommige editors voegen een tilde toe aan het bestand, terwijl aangepast wordt), wp-config.bak en nog een groot aantal andere extensies.
In een niet eens zo’n heel ver verleden nam ik het onderhoud van een WordPress site over van een concullega. Mijn nieuwe klant die wilde de hele site gecheckt hebben en één van de eerste dingen die ik zag, was dat de site eigenlijk wagenwijd open stond om gehackt te worden.
Mijn waarde concullega had namelijk de gewoonte om bij wijzigingen in de wp-config.php een versienummer in bestandsnaam op te nemen. Dus : wp-config.php.versie.1
Nu zullen niet veel hackers op Nederlandse termen in een bestandsnaam controleren, maar dit bestand was dus eigenlijk open en bloot toegankelijk op het internet.
Iedere plugin is een nieuw risico
Zelfs wanneer we uitgaan van de allerbeste bedoelingen van de programmeur, iedere plugin die je installeert in je WordPress site is een nieuw risico. Mensen maken fouten en op het Internet worden fouten vaak snel ontdekt en hard afgestraft.
Eén berucht recent voorbeeld is een fout die er tot en met versie 2.9.4 in Elementor Pro zat. Wanneer je meerdere gebruikers met publicatierechten op je site had (bijvoorbeeld gastbloggers die in kunnen loggen), dan was het mogelijk dat deze gebruiker, indien deze wist wat te doen, zichzelf meer rechten gaf en zo beheerder werd.
Het probleem van plugins (of modules / components of hoe het ook in andere CMS-en mag heten) is dat een plugin complete toegang tot je systeem heeft. En dat is ook nodig om te kunnen functioneren.
Vergelijk ik dat met bijvoorbeeld Shopify ‘apps’, het equivalent van ‘plugins’, maar dan voor Shopify, dan werkt dat heel anders.
In CMS-en die door PHP worden ‘aangedreven’ heeft de plugin per definitie toegang tot het filesystem en tot de database.
In Shopify apps heeft een app uitsluitend toegang tot een specifieke ‘interface’, een API. Dat komt omdat de communicatie hier compleet anders verloopt.
Een tweede probleem -dat hebben we in het voorbeeld met het wp-config.php probleem al gezien- is dat de code direct toegankelijk is vanaf het Internet.
In modernere (meestal niet PHP gerelateerde) technologieën is de codebase zelf op een compleet andere plaats dan de webdocumenten.
Oude -of erger nog- ‘nulled’ plugins en thema’s
Sommige WordPress plugins zijn aardig aan de prijs. En wanneer je enkele plugins gebruikt, waar je jaarlijke terugkerende kosten voor hebt, dan kan het bij elkaar toch een aardig bedrag worden.
Nu zijn er sites die zogenaamde ‘nulled’ plugins aanbieden. Zo’n plugin waar je voor moet betalen die zal namelijk op de één of andere manier contact zoeken met een server, daar één of andere bevestigingscode krijgen, dat de plugin inderdaad een licentie heeft, en dan gewoon verder bruikbaar zijn. Is die bevestiging er niet, dan werkt de plugin niet, of slechts gedeeltelijk.
Het is eigenlijk weinig moeite voor een ervaren programmeur om zo’n ‘licentie check’ uit de plugin te verwijderen. En er zijn talloze sites waarop ‘nulled versions’ van betaalde plugins worden aangeboden. Soms gratis, soms voor slechts enkele euro’s.
Wat is hier het gevaar?
Allereerst is het gevaar natuurlijk, dat je je plugin laat verouderen, omdat er geen automatische updates plaats zullen vinden. Maar een veel groter risico is, dat vaak dit soort ‘nulled’ plugins een ‘achterdeurtje’ hebben. Een manier waarop de maker van deze nulled plugins zich toegang kan verschaffen tot jouw website.
Ik kan je eigenlijk alleen maar adviseren ver weg te blijven van sites met nulled plugins. Levert een plugin je wat op? Dan is het ook waard om er voor te betalen. Levert het niets op? Waarom zou je hem dan nodig hebben?
Wat kan ik doen, om mijn site beter te beveiligen?
Er zijn genoeg concullega’s die uitgebreid bloggen over hun meest geliefde beveiligingsplugin. Het (niet zo aardige) is echter, dat in de praktijk een ’totale’ beveiligingsplugin je website nauwelijks veiliger zal maken. Maar laten we eerst eens kijken wat je er goed aan kan doen om in ieder geval je site een stuk veiliger te maken.
Laten we beginnen met een aantal voor de hand liggende zaken :
Gebruik SSL/HTTPS
Dat hoeft niets extra te kosten en is in enkele seconden geactiveerd. Doe het dus.
Maak back-ups
Ik kan het niet vaak genoeg zeggen. Een gehackte site herstellen kan honderden euro’s -zo niet meer- kosten, afhankelijk van de omvang van de schade. Een back-up kost je een paar minuten tijd.
Heb je een betrekkelijk statische website? Maak iedere keer net voor- en net na een verandering een back up.
Veranderen er dagelijks dingen aan je website? Maak dan minimaal een dagelijkse backup.
Update, update, update
Eén van de grootste oorzaken van ‘gehackte sites’ is ‘sites met oude software’. Update dus!
Veilige wachtwoorden
Het zal je wellicht verbazen, maar wanneer je een veilig wachtwoord gebruikt dan valt het helemaal niet mee om ‘zomaar’ in te breken in je website. Al helemaal niet, wanneer je ook nog eens gebruik maakt van een beveiliging tegen ‘brute force attacks‘ en ‘two way authentication‘.
De meeste WordPress websites worden dan ook helemaal niet op deze manier gehackt. Het blijft natuurlijk een goede gewoonte om er wel zorg voor te dragen, dat de kans op deze manier gehackt te worden minimaal is. Honderd procent voorkomen is nooit mogelijk.
‘Back up’ configuratie bestanden verwijderen
Zoals hierboven beschreven, ‘oude’ configuratiebestanden met andere dan PHP extensies zijn een groot gevaar voor de veiligheid van je website. Controleer of deze inderdaad niet voorkomen. Zijn ze er wel, verwijder ze dan.
Geen shared hosting
Het risico te worden gehackt is groter, wanneer je gebruik maakt van shared hosting (dit in contract met VPS of een dedicated server). Op een shared hosting server staan vaak 50-200 websites -afhankelijk van de hostingpartij. Is een server op ‘systeemniveau’ gecompromiteerd, dan zijn er gelijk tientallen websites gecompromiteerd.
Dit wil absoluut niet zeggen dat shared hosting ‘onveilig’ is, maar je loopt wel een groter risico.
XML-RPC uitzetten
XML-RPC is een protocol wat sinds WordPress 3.x (zo uit mijn hoofd 3.5) standaard geactiveerd werd. Het is een protocol waarmee je onder andere kan communiceren met web- en mobiele apps. In latere versies van WordPress is hiervoor ook de WP REST API toegevoegd. de REST API is niet alleen ‘moderner’, maar ook veiliger.
Het probleem met XML-RPC is -tenminste in de WordPress implementatie- dat het een geweldig doel is voor een brute force attack. Er is namelijk zoiets als de system.multicall functie in deze implementatie. In zo’n ‘system.multicall’ functie kan de hacker niet 1, maar gelijk honderden passwords richting server sturen om te proberen.
Heb je toch XML-RPC nodig? Dan kan je het ook heel selectief blokkeren.
Stel, dat jij een applicatie hebt die XML-RPC moet gebruiken. En die applicatie staat op server 1.2.3.4
Je kan dan heel simpel XML-RPC toestaan voor alleen dat IP adres, door de volgende code op te nemen in je .htaccess bestand in de WordPress root.
# Block WordPress XML-RPC requests
<Files xmlrpc.php>
order deny, allow
deny from all
allow from 1.2.3.4
</Files>
Natuurlijk vervang je ‘1.2.3.4’ met het IP adres wat je werkelijk toegang wilt geven.
Wil je helemaal geen toegang geven? Voeg dan het volgende toe aan je .htaccess bestand
# Block WordPress XML-RPC requests
<Files xmlrpc.php>
deny from all
</Files>
Denk er wel aan, dat bij tikfouten in een .htaccess bestand, je website down kan gaan. Pas deze bestanden dus altijd aan via FTP of de file manager in je hosting panel en niet vanuit de code editor in WordPress zelf.
Er is ook een plugin ‘Disable XML RPC‘, maar waarom zou je een plugin gebruiken voor iets wat je met enkele regeltjes tekst op kan lossen? Bovendien is de oplossing die in de plugin wordt aangeboden één die vanuit WordPress zelf wordt ‘uitgevoerd’. Met andere woorden, om het aanroepen van het bestand te stoppen, moet eerst WordPress geactiveerd worden, wat tijd kost.
De .htaccess oplossing houdt de aanroeper al tegen voor WordPress is opgestart.
Zorg ervoor dat er geen PHP code uitgevoerd kan worden uit ‘foute’ folders
Er zijn bepaalde folders binnen de WordPress bestandsstructuur waar geen programmacode hoort te staan. De belangrijkste hiervan is toch wel de ‘uploads’ folder, de folder waarheen plugins en ook WordPress zelf bestanden uploaden. Nu ‘beschermt’ de media uploader je tegen ‘foute bestanden’. Standaard kan je bijvoorbeeld bestanden van bepaalde typen niet uploaden.
Dat is echter te omzeilen. En het is niet ondenkbaar, dat bepaalde plugins die de media uploader aanroepen eigenlijk de media uploader toestaan teveel te uploaden. Zoals bijvoorbeeld PHP bestanden.
Om te voorkomen dat zo’n PHP bestand ook door kwaadwillende mensen uitgevoerd kan worden, is het goed om voor alle PHP bestanden een vergelijkbare truc uit te halen, die we al met de xmlrpc.php hebben uitgehaald.
We gaan hiervoor naar de folder wp-content/uploads en in deze folder maken we een bestand .htaccess aan. Let op de punt aan het begin van het bestand.
In dit bestand zetten we de volgende code
# Deny access to .php files
<Files *.php>
deny from all
</Files>
Eenzelfde bestand met eenzelfde inhoud mag je ook in de folder wp-includes/ plaatsen. Want ook hier hoort geen PHP code te staan.
Wat is er fout met ‘security plugins’ voor WordPress?
Voor alle duidelijkheid, er is niets ‘fout’ met security plugins voor WordPress, maar met uitzondering van de Sucuri plugin wordt er aan de verkeerde kant beveiligd. En dit om twee redenen.
Eenmaal binnen is de plugin gecompromiteerd
Eén belangrijke reden, waarom dit soort plugins maar matig werkt, is dat zodra de plugin faalt, de hacker binnen is. Want wanneer je eenmaal door de WordPress beveiliging heen bent gebroken heb je vrij spel binnen WordPress.
Web Application Firewalls zijn inefficient
Plugins als WordFence, All in One Security and Firewall, Defender en andere vergelijkbare plugins proberen WordPress te beschermen… en gebruiken daarbij… WordPress.
Eén van de dingen die ik juist graag wil is, dat WordPress uitsluitend bezig is met dingen die WordPress moet doen. Pagina’s en blogposts laten zien bijvoorbeeld.
Wanneer ik (veel) verkeer krijg wat iedere keer weer wordt tegengehouden door mijn firewall plugin… en mijn firewall plugin dit allemaal netjes logt, dan is WordPress heel druk met de verkeerde activiteiten.
DNS Level Firewalls
Eén manier om veel ‘fout verkeer’ tegen te houden is gebruik te maken van een DNS level firewall. Een aardig voorbeeld hiervan is Cloudflare. Cloudflare doet twee dingen. Het eerst is, dat je ip adres ‘verborgen’ wordt gehouden voor de buitenwereld. Het tweede is, dat heel veel van het ‘foute’ verkeer op dat niveau al tegen wordt gehouden. De meeste kwaadwillenden komen niet eens aan bij je website. Dit verkeer belast jouw systeem dus totaal niet.
Application level Firewalls
Application level firewalls zitten net een stapje voor WordPress. Het verkeer is inmiddels op je site aangekomen, maar heeft nog geen toegang gekregen tot specifieke applicaties (denk aan de webserver, database etc). Sucuri is bijvoorbeeld een firewall die op dit niveau opereert (met een handige interface plugin in WordPress zelf, maar de beveiliging zelf vindt hoofdzakelijk buiten WordPress plaats).
Zelf gebruik ik geen Sucuri, maar een firewall die deel uitmaakt van mijn Plesk beheersoftware, maar het idee is hetzelfde.
Iemand die op wat voor wijze dan ook toegang heeft gekregen tot je website heeft daarmee nog geen toegang tot je complete systeem!
En hoewel een ‘Application level firewall’ wel enig beslag legt op je systeemresources, kost het je veel minder resources dan bijvoorbeeld een plugin als WordFence.
Malware scanners
Opnieuw, er zijn verschillende malware scanners als WordPress plugin in omloop, maar die zien niets meer (of minder) dan een externe (aan de WP website) Malware scanner. Sucuri bevat een goede Malware scanner. Hetzelfde is het geval met Plesk panel (de malware scanner die ik gebruik).
Moraal van het verhaal…
Ik ben begonnen aan dit blogartikel omdat een klant mij vroeg ‘wat een betere WordPress plugin is voor beveiliging’. De drie plugins die hij noemde waren naar mijn idee geen van drieën echt een grote verbetering van je veiligheid.
Wat heb je aan een securityplugin, die je vertelt, dat er nog 12 updates staan te wachten als je deze toch niet uitvoert?
WordPress zelf vertelt je dit ook al.
Een veilige WordPress website is niet het gevolg van een ‘beveiligingsplugin’, maar van ‘veilig werken’. En ik hoop dat ik met dit artikel je wat meer inzicht en motivate heb mogen geven ‘veilig aan de slag te gaan’ en te blijven.
Vind je al dit ‘dichttimmeren’ via .htaccess toch een beetje eng? Ik kan het ook voor je doen via een WordXPression Support Strippenkaart.