Stuurt je website bezoekers door naar een goksite, een datingsite of een vage webshop, dan is je site vrijwel zeker gehackt. De omleiding zit in je thema, in een plugin, in het bestand .htaccess, in de kernbestanden van WordPress of in de database — en hij is zo gebouwd dat jij hem niet ziet. Vaak werkt hij alleen voor mobiele bezoekers, alleen voor wie via Google binnenkomt en nooit voor wie is ingelogd; dat selectieve tonen heet cloaking. Hieronder lees je hoe je de omleiding zichtbaar maakt, waar hij meestal zit, hoe je hem weghaalt zonder dat hij terugkomt en wat je daarna met Google doet.
Correcthosting uit Beverwijk (hostingbedrijf sinds 2006) haalt de omleiding en de bijbehorende achterdeurtjes weg voor € 50 inclusief btw per website, meestal binnen een uur, elke dag van 08:00 tot middernacht via WhatsApp of telefoon — ook als je site elders gehost is. Staat je site bij ons, dan controleren we ook op serverniveau.
Waarom jij niets ziet en je bezoekers wel
Een omleiding levert de hacker alleen iets op zolang die onopgemerkt blijft: elke bezoeker die op de goksite belandt is een paar cent affiliatevergoeding, en een eigenaar die het merkt haalt de code weg. Daarom kijkt de code eerst wie er binnenkomt voordat hij doorstuurt. Ben je ingelogd in WordPress, dan gebeurt er niets — de inlogcookie verraadt je. Typ je het adres rechtstreeks in, dan gebeurt er ook niets; pas wie via een zoekresultaat van Google of Bing binnenkomt, wordt doorgestuurd. Veel varianten kijken ook naar het apparaat: een telefoon krijgt de omleiding, een desktop de gewone site. En na de eerste omleiding zet de code een cookie, zodat dezelfde bezoeker de tweede keer de normale site ziet en denkt dat hij zich vergiste.
Tel dat bij elkaar op en je snapt waarom je het van klanten hoort terwijl je zelf niets vindt: jij bent ingelogd, je typt het adres in, je zit achter een desktop en je hebt de site vandaag al tien keer geopend. Voor de code ben je precies de bezoeker die met rust gelaten moet worden.
Zo maak je de omleiding zichtbaar
Doe je alsof je een onbekende bezoeker bent, dan komt de omleiding vanzelf tevoorschijn. Open je site in een incognitovenster: daar ben je niet ingelogd en zijn er geen cookies. Pak daarna je telefoon, zet de wifi uit en open de site via 4G of 5G, zodat je van een ander IP-adres komt en een mobiele browser gebruikt. Zoek vervolgens in Google op je bedrijfsnaam en klik vanuit het zoekresultaat door in plaats van het adres in te typen. Gebruik voor elke poging een nieuw incognitovenster, want na één omleiding staat er een cookie en lijkt alles weer normaal.
Wil je meer zekerheid, dan vraag je de pagina op zoals een zoekmachine dat doet. Vanaf een computer met een terminal, liefst op een andere locatie dan je kantoor:
curl -s -o /dev/null -D - -A "Googlebot/2.1 (+http://www.google.com/bot.html)" -e "https://www.google.com/" https://jouwdomein.nl/
Staat er in het antwoord een regel Location: met een ander domein, dan stuurt de server zelf door en zit de omleiding in .htaccess of in PHP. Krijg je een gewone 200, haal de pagina dan op met een mobiele browser als user-agent en zoek in de bron naar scripts van domeinen die je niet kent:
curl -s -A "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)" https://jouwdomein.nl/ | grep -io "<script[^>]*src=[^>]*>"
Alles wat daar staat en niet van je eigen domein, je thema of een plugin komt, verdient een tweede blik. Het onderscheid tussen een Location-header en een script in de pagina vertelt je meteen in welke hoek je moet zoeken. Ook Search Console helpt: de URL-inspectie kan een pagina live testen en laat zien wat Googlebot te zien krijgt.
Waar de omleiding meestal zit
De omleiding is nooit één bestand. Wat je ziet is het eindpunt; daaromheen zitten de stukjes die hem laden en de achterdeurtjes die hem terugzetten. Dit zijn de plekken waar hij in de praktijk zit, ongeveer op volgorde van hoe vaak we ze tegenkomen.
In je thema
De simpelste variant: een <script>-regel vlak voor </head> of </body> in header.php of footer.php, of een stuk PHP in functions.php dat via de wp_head-hook een script in elke pagina zet. De code is meestal onleesbaar gemaakt met eval, String.fromCharCode of atob, en staat vaak op één lange regel na honderden lege regels, zodat het bestand op het eerste gezicht normaal lijkt. Kijk naar de wijzigingsdatum van de thema-bestanden en vergeet het child-thema niet. Ook het veld voor extra CSS of eigen HTML in de Customizer is een geliefde plek; die inhoud staat niet in een bestand maar in de database.
In de database: wp_options en wp_posts
Zijn siteurl en home in de tabel wp_options veranderd in een ander domein, dan stuurt WordPress élke pagina door en kun je zelf niet eens meer inloggen. Dat herstel je via phpMyAdmin of de databasetool van je hoster. Subtieler zijn scripts in widget-opties (widget_text, widget_custom_html, widget_block) en in de thema-instellingen (theme_mods_…): die worden op elke pagina meegeladen en verschijnen nergens in een bestand. In wp_posts plakken hackers een script achter de inhoud van elk bericht en elke pagina, honderden keren dezelfde regel. En let op de optie cron: een geplande taak die elk uur de code opnieuw wegschrijft, is de reden dat een "verwijderde" omleiding na een dag terug is.
Zoeken doe je met een query op %<script% in option_value en in post_content. Vind je iets, kijk dan meteen ook in wp_users en in tabellen met een afwijkende prefix — verstopte beheerdersaccounts zitten daar geregeld naast.
In .htaccess
Een omleiding op serverniveau ziet er in .htaccess uit als een RewriteCond op de user-agent (android|iphone|ipad) of op de referer (google|bing|yahoo), gevolgd door een RewriteRule naar het vreemde domein met [R=302,L]. Soms staat die na honderden lege regels onder de gewone WordPress-regels, zodat je bij het openen een normaal bestand ziet. Ook ErrorDocument-regels die naar een externe URL wijzen komen voor, net als extra .htaccess-bestanden in wp-content en wp-content/uploads. Deze variant herken je aan de Location-header uit de test hierboven.
In de kernbestanden van WordPress
Bestanden als index.php, wp-load.php, wp-settings.php, wp-blog-header.php en de bestanden in wp-includes zitten bij elke pagina in de laadketen. Eén regel @include naar een bestand met een onschuldige naam is genoeg: die regel is de loader, en het bestand waarnaar hij wijst haalt de eigenlijke omleiding op. Wat we in ons eigen serverbeheer tegenkwamen: een site die niet doorstuurde maar een 500-fout gaf, omdat een loader in vijf kernbestanden was geïnjecteerd. Wie alleen het thema en de plugins had vervangen, had de site niet gerepareerd, en wie alleen de foutmelding had opgelost, had de omleiding laten staan.
PHP in de uploads-map en nepplugins
In wp-content/uploads horen afbeeldingen en documenten, geen PHP. Elk PHP-bestand dat je daar vindt is een achterdeur, ongeacht de naam. Kijk ook in wp-content/mu-plugins: alles in die map wordt automatisch geladen zonder activatie en staat niet in je gewone pluginlijst. Nepplugins met een naam die klinkt als een hulpprogramma van WordPress zelf horen in dezelfde categorie. Dit is zelden de omleiding zelf, maar wel de reden dat hij terugkomt.
Zo haal je hem weg zonder dat hij terugkomt
Maak eerst een volledige back-up, ook van de besmette staat; die sporen heb je later nodig om de ingang te vinden. Vervang daarna wp-admin, wp-includes en alle losse PHP-bestanden in de hoofdmap door verse kopieën van wordpress.org — alleen wp-config.php blijft staan, en die lees je regel voor regel na op include-regels die er niet horen. Doe hetzelfde met je thema en elke plugin, met verse downloads van de officiële bron. Een gekraakt (nulled) premium-thema gooi je weg; daar zat de ingang waarschijnlijk in. Zet een standaard .htaccess terug en verwijder de extra exemplaren in submappen. Haal alle PHP uit wp-content/uploads en controleer mu-plugins.
Dan de database: herstel siteurl en home, haal de scripts uit widgets, thema-instellingen en berichten, verwijder de vreemde cron-taak, en zoek-en-vervang het spamdomein in de hele database. Verwijder beheerders die je niet kent, ook die in tabellen met een andere prefix. Vernieuw daarna álle wachtwoorden — WordPress, FTP of SFTP, database en hostingpaneel — en zet nieuwe beveiligingssleutels (salts) in wp-config.php, zodat gestolen sessiecookies waardeloos worden.
Scan tot slot opnieuw, en niet één keer. Een herscan van een besmette site vindt geregeld nog iets wat de eerste ronde miste. Schoon is een site pas als een verse scan, buiten WordPress om, nul treffers geeft. Is je site bij ons gehost, dan kijken we daarbij ook op serverniveau naar cronregels en andere accounts op dezelfde server. De volledige volgorde, inclusief wat je in het eerste uur doet, staat in WordPress-site gehackt: dit doe je eerst; wat het kost om het uit handen te geven lees je in WordPress-malware verwijderen: wat kost het?.
Wat je daarna met Google doet
Een omleiding gaat vrijwel altijd samen met spampagina's die alleen aan Googlebot worden getoond, dus zoek op site:jouwdomein.nl en kijk of er casino- of medicijnpagina's tussen staan. Meld je site aan bij Search Console en kijk onder Beveiligingsproblemen: staat daar een melding, dan blijft "Deze site is mogelijk gehackt" of het rode waarschuwingsscherm staan tot je een herbeoordeling aanvraagt. Doe dat pas als de site echt schoon is; een afgewezen herbeoordeling kost je weken. Hoe je dat aanpakt en wat je in de tussentijd tegen klanten zegt, staat in 'Deze site is mogelijk gehackt' in Google: wat het betekent. Adverteer je via Google Ads, controleer dan ook of je advertenties niet zijn afgekeurd: Google keurt advertenties af naar een site die bezoekers doorstuurt.
Zo voorkom je een tweede keer
De omleiding is het gevolg; de oorzaak is de ingang. In verreweg de meeste gevallen is dat een verouderde plugin of thema met een bekend lek, een zwak of hergebruikt wachtwoord, een gekraakt thema met ingebouwde achterdeur of een oude PHP-versie. Houd alles automatisch bijgewerkt met een back-up achter de hand, gebruik unieke wachtwoorden en tweestapsverificatie op alle beheerdersaccounts, verwijder wat je niet gebruikt en zorg dat je back-ups buiten de site zelf staan. Controleer daarnaast elke week één keer van buitenaf — incognitovenster, telefoon zonder wifi — of je site nog gewoon je site is. Alle maatregelen op een rij staan in WordPress-site beveiligen: 11 praktische tips. Liever geen omkijken? WordPress-onderhoud voor € 150 per jaar (excl. btw) doet nachtelijke updates, malwarescans en back-ups, zodat een lek gedicht is voordat iemand het gebruikt.
