WP-beveiliging: wp-admin beveiligen | login-URL wijzigen, inlogpogingen beperken, XML-RPC

Affiliatemelding v3.1
Affiliatemelding v3.2 (mobiel)

wp-admin beveiligen doe je met instellingen die brute-force-aanvallen op het beheerscherm en het inlogscherm van WordPress tegenhouden. Toen ik de toegangslogs bekeek van een Nginx + Apache-server waarop meerdere WordPress-sites draaien, bleven er automatische verzoeken naar xmlrpc.php binnenkomen, ook nadat de login-URL was gewijzigd. Daarom heb ik er ook een snelheidsbeperking op serverniveau bij gezet.

1️⃣ Waarom wp-admin en wp-login.php worden aangevallen

Dat het beheeradres van WordPress algemeen bekend is, is een zwakke plek, maar met betere beveiliging kun je dat opvangen. Elke WordPress-site gebruikt dezelfde /wp-admin/ en [wp-login.php], en open je /wp-admin/ terwijl je bent uitgelogd, dan kom je op het inlogscherm van [wp-login.php] terecht.

Aanvallen komen binnen als brute force: op dit inlogscherm worden telkens opnieuw gebruikersnamen en wachtwoorden geprobeerd. Daarom gaat wp-admin beveiligen eerst om het tegenhouden van inlogpogingen en pas daarna om het verbergen van het adres.

Twee ingangen naar de WordPress-login
Via de browser
/wp-admin/
Uitgelogd: doorgestuurd naar het inlogscherm (302)
wp-login.php
Inlogscherm · gebruikersnaam en wachtwoord invullen
Apps · automatische verzoeken
xmlrpc.php
Gebruikersnaam en wachtwoord gaan zonder inlogscherm mee in een POST-verzoek
Slaat het inlogscherm over
Met system.multicall meerdere wachtwoorden in één verzoek · het adres blijft hetzelfde, ook als je de login-URL wijzigt
Zelfde controle van gebruikersnaam en wachtwoord
Beide ingangen controleren het account met dezelfde authenticatiefunctie van WordPress
Brute-force-aanvallen komen binnen via de ingang die openstaat. Het wijzigen van de login-URL geldt alleen voor de bovenste ingang, dus xmlrpc.php sluit je apart af of je beperkt het aantal verzoeken.

2️⃣ Wat het wijzigen van de login-URL wel en niet doet

Wijzig je de login-URL met een beveiligingsplugin, dan geeft de standaard [wp-login.php] een 404-fout, zodat automatische aanvallen die het standaardadres blijven bestoken het inlogscherm niet eens bereiken. Het nieuwe adres moet je apart doorgeven aan iedereen met een beheerdersaccount.

🧭 Ingangen naar de WordPress-login
Uitlegdiagram
⬜ Geen plugin
🛡️ Hide My WP
🚪 Login-ingang
/wp-login.php · /wp-admin/Hetzelfde adres op elke WordPress-site
Inlogscherm404
/newloginGewijzigd adres · alleen beheerders kennen het
Inlogscherm
POST /xmlrpc.phpControleert het wachtwoord zonder inlogscherm
Antwoordt op de wachtwoordcontroleUitgeschakeld 405
Gemeten op een testsite · verzoeken terwijl uitgelogd
→
🤖 Automatische aanvallen
Ingangen waar wachtwoorden op een bekend adres kunnen worden geprobeerd
2
1
Geen
Zonder plugin zijn er twee plekken om wachtwoorden te proberen: [wp-login.php], dat op elke WordPress-site hetzelfde is, en [xmlrpc.php], dat wachtwoorden controleert zonder inlogscherm.
Na het wijzigen van de login-URL geven [wp-login.php] en /wp-admin/ een 404, maar [xmlrpc.php] antwoordt nog altijd of de gebruikersnaam en het wachtwoord kloppen.
Schakel je ook XML-RPC uit, dan eindigen inlogverzoeken aan [xmlrpc.php] met het antwoord dat de XML-RPC-dienst is uitgeschakeld, en kunnen wachtwoorden op een bekend adres niet meer worden geprobeerd.

Deze methode kost weinig moeite, maar vergeet je het nieuwe adres, dan kom je niet meer in het beheerscherm en moet je de plugin uitschakelen door de map ervan via FTP of een bestandsbeheerder te hernoemen. Beheren meerdere mensen de site, leg het adres dan op één plek vast.

3️⃣ Inlogpogingen beperken en tweestapsverificatie

Ook met een gewijzigde login-URL gaan de pogingen om het wachtwoord te raden gewoon door zodra het nieuwe adres bekend raakt. De WordPress-kern kent geen limiet op mislukte inlogpogingen: hoe vaak je ook een verkeerd wachtwoord invult, hetzelfde inlogscherm gaat steeds opnieuw open.

🧭 Inlogpogingen beperken en tweestapsverificatie
Uitlegdiagram
⬜ Geen plugin
🛡️ Beveiligingsplugin
🔑 Inloggen vanaf hetzelfde IP
1eVerkeerd wachtwoord
Weer het inlogschermNog 3 pogingen
2eVerkeerd wachtwoord
Weer het inlogschermNog 2 pogingen
3eVerkeerd wachtwoord
Weer het inlogschermNog 1 poging
4eVerkeerd wachtwoord
Weer het inlogscherm20 min geblokkeerd
5eGeblokkeerdVerkeerd wachtwoordLogin · XML-RPC-verzoeken
Weer het inlogschermOok xmlrpc.php 403
Wachtwoord invoerenJuist wachtwoord
Scherm voor de code
Authentication Code6 cijfers uit de authenticator-app · elke 30 s nieuw
Beheerscherm
Aanvaller die alleen het wachtwoord kentKent de code niet
Strandt op het codescherm
Gemeten op een testsite · opeenvolgende verzoeken vanaf hetzelfde IP
→
🤖 Automatische aanvallen
Kunnen wachtwoorden blijven worden geprobeerd?
Geen limiet
Bij de 4e geblokkeerd
Strandt op de code
Zonder plugin gaat hetzelfde inlogscherm elke keer weer open, ook als je vanaf hetzelfde IP zes keer een verkeerd wachtwoord invult.
Met een limiet op inlogpogingen zie je na elke fout hoeveel pogingen je nog hebt, en na de 4e mislukte poging kan dat IP 20 minuten niet inloggen. Tijdens de blokkade eindigen ook verzoeken aan xmlrpc.php met een 403.
Met tweestapsverificatie gaat het beheerscherm ook bij een juist wachtwoord pas open nadat je de 6-cijferige [Authentication Code] hebt ingevuld die de authenticator-app elke 30 seconden opnieuw aanmaakt.

Een plugin die inlogpogingen beperkt, blokkeert een IP een tijdlang zodra het toegestane aantal pogingen is overschreden, en tweestapsverificatie vraagt ook bij een juist wachtwoord nog om een code uit de authenticator-app op je telefoon. Zet je tweestapsverificatie aan, bewaar dan ook de back-upcodes voor als je je telefoon kwijtraakt.

4️⃣ xmlrpc.php afsluiten

[xmlrpc.php] is een tweede ingang die een gebruikersnaam en wachtwoord aanneemt zonder via het inlogscherm te gaan, en met de methode [system.multicall] kunnen in één verzoek meerdere wachtwoorden worden geprobeerd.

In de toegangslogs van een Nginx + Apache-server waarop meerdere WordPress-sites draaien, kwamen op 13 oktober tussen 0:00 en 9:50 uur 2.250 POST-verzoeken naar [xmlrpc.php] binnen. Ze kwamen van 22 IP-adressen, en de User-Agent deed zich voor als Jetpack en WordPress.com.

Gebruik je de mobiele WordPress-app of Jetpack niet, blokkeer dan verzoeken aan [xmlrpc.php] in de Nginx-configuratie of gebruik de instelling om XML-RPC uit te schakelen in een beveiligingsplugin.

# In het server-blok — verzoeken aan xmlrpc.php weigeren
location = /xmlrpc.php {
    deny all;
}

Met deze instelling eindigen alle GET- en POST-verzoeken aan [xmlrpc.php] met een 403 zonder dat ze PHP bereiken. De XML-RPC-uitschakeling van een beveiligingsplugin weigert alleen verzoeken waarvoor een login nodig is, terwijl het bestand blijft antwoorden; wil je ook het aantal PHP-uitvoeringen omlaag brengen, dan blokkeer je het beter in Nginx.

5️⃣ Blokkeren op de server: beheertoegang per IP beperken en snelheidsbeperking

Beheer je de site alleen vanaf een vast IP-adres, dan is de zekerste methode om [wp-login.php] en /wp-admin/ in Nginx alleen voor dat IP open te zetten. Voor situaties waarin het IP thuis of op kantoor vaak verandert, is dit niet geschikt.

Je zou denken dat je dan heel /wp-admin/ kunt afsluiten, maar functies aan de bezoekerskant, zoals zoeken of een winkelwagen, sturen vaak verzoeken naar [admin-ajax.php], dus dat bestand moet openblijven.

# In het server-blok — boven de PHP-location
location = /wp-login.php {
    allow 203.0.113.10;   # Je vaste IP-adres voor beheer
    deny all;
    # Kopieer hieronder de instellingen van je PHP-location
}

Open je [wp-login.php] vanaf een ander IP dan het opgegeven adres, dan krijg je een 403; vanaf het opgegeven IP gaat het inlogscherm open. Binnen de location moet je de PHP-instellingen van de site (fastcgi_pass enzovoort) ongewijzigd overnemen, anders werkt het inlogscherm niet goed.

Kun je je IP niet vastzetten, dan kun je een snelheidsbeperking zetten op PHP-verzoeken van bezoekers die niet zijn ingelogd. Hoe ik die op 30 per minuut heb gezet, zodat automatische verzoeken de serverbronnen niet kunnen opslokken, wordt in het artikel php-fpm max_children-waarschuwing uitgelegd.

# http-blok — alleen verzoeken zonder login-cookie tellen, per IP
map $http_cookie $php_anon_key {
    default                 $binary_remote_addr;
    "~*wordpress_logged_in" "";
}
limit_req_zone $php_anon_key zone=php_anon:10m rate=30r/m;

# In de PHP-location
limit_req zone=php_anon burst=60 nodelay;
limit_req_status 429;

Stuurt één niet-ingelogd IP achter elkaar PHP-verzoeken, dan worden er tot en met de 61e verwerkt en daarna wordt 429 teruggegeven; verzoeken met een login-cookie tellen niet mee. Als een paginacache antwoordt zonder via PHP te gaan, merken gewone bezoekers die pagina's bekijken niets van deze limiet.

ℹ️ Affiliatemelding
De content van deze site bevat affiliatelinks. Koopt een bezoeker via een van deze links een product of dienst, dan ontvangt deze site een commissie van de verkoper. Het bedrag dat de koper betaalt (bij acties gaat het omlaag ↓) wordt daardoor niet hoger. De vermelde prijzen, kortingen en voorraad gelden op het moment van schrijven en kunnen afwijken; controleer ze daarom vóór je aankoop bij de verkoper. Producten worden gekozen en beoordeeld volgens onze eigen criteria, en commissies hebben geen invloed op de volgorde of de inhoud van de beoordelingen.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Laat zien dat je geen machine bent: 1   +   7   =