
Et skjult WordPress-login kan reducere støj fra simple bots. Det lukker ikke WordPress’ øvrige autentificerings- og identitetsflader.
Din loginadresse kan være flyttet til /hemmelig-8471. Det ændrer ikke, at WordPress stadig kan kontrollere kontooplysninger gennem xmlrpc.php, og at REST API’et kan bruges til at bekræfte en offentlig forfatters login-navn. Det er ikke fire zero-days. Det er dokumenteret standardadfærd. Og netop derfor kan en hemmelig login-URL ikke regnes som adgangskontrol.
Denne artikel viser de relevante flader, hvordan du selv kan verificere dem på et testmiljø, du ejer, og hvordan de kan lukkes. Jeg har samlet lukningerne i et gratis plugin fra Nielco IT, som jeg introducerer undervejs. Først beviserne, så løsningen.
Indhold
- Hvad et skjult login faktisk gør
- De tre vigtigste beviser
- Derfor byggede vi et plugin
- Hvad pluginnet lukker, og hvad det bevidst ikke lukker
- Flere flader
- Har du allerede Wordfence?
- Installation og download
- Teknisk appendiks
1. Hvad et skjult login faktisk gør
Lad os være præcise, for upræcise påstande giver tekniske læsere en let vej til at afvise hele pointen.
Et skjult login flytter login-formularen til en hemmelig sti. Det kan reducere støj fra primitive bots, mindske belastningen på login-siden og fjerne en del opportunistiske forsøg. Det er reelt nok, men det er støjreduktion, ikke adgangskontrol.
WordPress-projektets egen holdning er, at brugernavne og bruger-ID’er ikke er hemmelige. Den offentlige adgang til REST API’ets brugerendpoint er tilsigtet. WordPress betragter brugernavnet som en identifikator og passwordet som verifikationen. Derfor kalder jeg ikke det følgende for sårbarheder, men autentificeringskanaler, enumeration-kanaler og kontrolfejl. Det er mere præcist, og det er sværere at skyde ned.
2. De tre vigtigste beviser
Eksemplerne nedenfor viser dokumenteret WordPress core-adfærd og kan bruges til at kontrollere din egen installation. Sikkerhedsplugins, serverregler og andre tilpasninger kan ændre det konkrete svar. Kør kun kommandoerne mod et miljø, du selv ejer eller har udtrykkelig tilladelse til at undersøge. De gætter ikke passwords.
Bevis 1: XML-RPC autentificerer uden om login-siden
Filen xmlrpc.php ligger på en fast sti og er som standard aktiv. Metoden wp.getUsersBlogs tager brugernavn og password og verificerer dem, uafhængigt af hvor login-siden er flyttet hen.
curl -sS -i -H 'Content-Type: text/xml' --data-binary @- \
https://ditmiljø/xmlrpc.php <<'XML'
<?xml version="1.0"?>
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value><string>DIN_TESTBRUGER</string></value></param>
<param><value><string>DIT_TESTPASSWORD</string></value></param>
</params>
</methodCall>
XML
Korrekt password giver bloglisten. Forkert giver en generisk 403-fejl. Auth-beslutningen træffes her, ikke på login-siden. En præcisering, som ældre artikler ofte får forkert: system.multicall giver ikke længere brute force-amplifikation, fordi WordPress lader det første mislykkede login i et multicall fejle alle efterfølgende. Byg derfor ikke argumentet på multicall.
Bevis 2: REST API’et viser offentlige forfatteridentiteter
For uautentificerede forespørgsler returnerer /wp-json/wp/v2/users de brugere, der har publiceret indhold i REST-eksponerede posttyper. Følsomme felter som email og roller undertrykkes. Svaret indeholder id, name og slug.
curl -s https://ditmiljø/wp-json/wp/v2/users
Feltet slug er brugerens user_nicename, ikke user_login. Feltet name er display_name. Selve user_login vises kun i autentificeret edit-kontekst. På mange installationer er user_nicename oprindeligt afledt af user_login og kan derfor være identisk med login-navnet eller ligge meget tæt på. Men det er forskellige databasefelter og kan have forskellige værdier.
Bevis 3: REST kan bekræfte et gættet login-navn
Fra WordPress 6.8 understøtter brugerendpointet parameteren search_columns, hvor user_login er en gyldig søgekolonne for en bruger uden list_users. Selv om user_login ikke returneres i svaret, kan en søgning bekræfte, om et gættet login-navn tilhører en offentlig forfatter. API-værdien username oversættes direkte til user_login.
curl -sS -i -G --data-urlencode 'search=wp-test-login-8471' \
--data-urlencode 'search_columns[]=username' \
--data-urlencode '_fields=id,name,slug' \
'https://ditmiljø/wp-json/wp/v2/users'
Kør samme forespørgsel med en tilfældig værdi og sammenlign X-WP-Total i svaret. Et match bekræfter et gyldigt login-navn. Resultaterne er fortsat begrænset til brugere med publiceret indhold. Plugins og WAF-regler kan ændre det observerede svar. Det er et stærkere og mere præcist bevis end at hævde, at slug altid er login-navnet.
Author-arkivet er den enkle variant af samme lækage: ?author=1 kan redirecte til en author-URL, der indeholder user_nicename, og afsløre login-navnet eller en tæt variant.
3. Derfor byggede vi et plugin
De tre beviser har en ting til fælles. Ingen af dem går gennem login-siden. En autentificering kan ske uden om den, og forfatteridentiteter er offentlige eller kan bekræftes. Et målrettet credential-angreb kræver en gyldig kontoidentifikator og en aktiv autentificeringskanal. Enumeration leverer den første. At skjule login-siden ændrer ingen af delene.
Jeg har samlet de afgrænsede lukninger i et gratis WordPress-plugin fra Nielco IT: Nielco IT Login & Enumeration Hardening. Det ændrer ikke login-URL’en og forsøger ikke at være en komplet sikkerhedspakke. Det lukker de konkrete core-flader, artiklen gennemgår, med målrettede WordPress-hooks og uden persistent tilstand, tællere, scanner eller eksterne kald.
4. Hvad pluginnet lukker
| Kontrol | Faktisk adfærd |
|---|---|
| XML-RPC | Deaktiverer autentificerede metoder og fjerner core-pingback |
| Application Passwords | Deaktiveres som standard |
| REST users | Fjerner offentlig user-collection og numeriske user-ID-ruter for uindloggede |
| Author-requests | Normaliseres til en tom 404 for uindloggede, kendte som ukendte slugs |
| oEmbed | Fjerner author_name og author_url |
| Sitemap | Fjerner core-brugersitemapet |
| Feeds | Erstatter postforfatterens navn med “Anonym” |
| Login-fejl | Generaliserer kun enumeration-relevante fejl, øvrige bevares |
| Visningsnavn | Advarer, hvis display_name matcher user_login, for op til 200 konti |
Fordi pluginnet afregistrerer selve REST-ruten frem for at matche en URL, dækker det både /wp-json/ og ?rest_route=, både collection og enkelt-ID, og lukker samtidig username-søgeoraklet. Det er en styrke, en ren WAF-URL-regel ikke har.
Hvad pluginnet bevidst ikke lukker
Det er et målrettet lag for de flader, det omfatter, ikke en samlet sikkerhedspakke. Det lukker ikke:
- Password-reset-oraklet, hvor reset-flowet afslører kendte konti og mails.
- Forfattermetadata eksponeret af temaer eller andre plugins.
- Custom REST- eller login-ruter.
- Hele
xmlrpc.php, kun de autentificerede metoder. - Sikkerheden, hvis XML-RPC eller Application Passwords genaktiveres.
En vigtig grænse: REST- og author-kontrollerne gælder uindloggede besøgende. Indloggede brugere springes over, så blokeditor, author-vælgere og andre redaktionelle funktioner ikke brydes. På et site med åben brugerregistrering kan en angriber derfor oprette en abonnent- eller kundekonto og igen nå de offentlige forfatterflader. Den grænse skal indgå i risikovurderingen.
Pluginnet indeholder ikke brute force-spærring, CAPTCHA eller WAF. Jeg har bevidst placeret de kontroller uden for pluginnet, fordi de kræver en anden arkitektur og normalt håndteres mere robust foran PHP, på CDN- eller webserver-niveau. Kombinér derfor pluginnet med to-faktor og rate limiting eller WAF.
5. Flere flader
De tre beviser ovenfor er de vigtigste. De øvrige flader, oEmbed, feeds, author-sitemap, Application Password-fejlrespons og de alternative ruter, ligger i det tekniske appendiks sidst i artiklen.
Den fulde reproducerbare testmatrix, med WordPress- og PHP-versioner, serveropsætning, forventede og observerede svar samt test som anonym, abonnent og administrator, hører hjemme i pluginnets tekniske dokumentation og kodeoversigt, ikke i denne artikel.
6. Har du allerede Wordfence?
Kontrollér indstillingerne frem for at antage, at de er aktive. Wordfence har egne kontroller for user enumeration, Application Passwords, login-fejl og XML-RPC. Wordfence deaktiverer Application Passwords som standard og har en enumeration-beskyttelse, der dækker ?author=N, oEmbed, REST-brugerendpointet og WordPress XML-sitemaps. Wordfence har generel brute force-beskyttelse samt særskilte indstillinger for XML-RPC-autentificering og 2FA. Den konkrete adfærd bør testes på den installerede version og konfiguration.
Nielco-pluginnet er derfor primært relevant, når du ønsker et lille, deklarativt lag uden scanner, WAF, logging og eksterne kald, eller når din hosting fraråder ressourcetunge sikkerhedsplugins.
7. Installation og download
Nielco IT Login & Enumeration Hardening er et lille, åbent plugin, der lukker de core-flader, artiklen gennemgår. Det foretager ingen eksterne kald, gemmer ingen trafikdata og indeholder ingen scanner, CAPTCHA eller hjemmelavet WAF.
- Version: 2.0.3
- Licens: GPL-2.0-or-later
- PHP: 7.4 eller nyere
- WordPress core-baseline i artiklen: 7.0.2
- Dokumenteret kompatibilitet: testet til 6.8. Kompatibilitetstest på 7.0.2 er planlagt, og “Tested up to” opdateres, når matricen er kørt.
- SHA-256 (zip):
d9aef79a4cab6d5f014cba6a758e5a9d92fb499b1754db76d47d2ab5960d5717
Foretrækker du ikke at installere et plugin, kan hver lukning laves med få målrettede WordPress-hooks. Læg dem i et lille must-use plugin frem for i temaets functions.php, så sikkerhedskoden ikke forsvinder ved et temaskift.
Kernekonklusion
Login-URL’en er en adresse. Den er ikke en legitimation. Skjul den gerne for at reducere automatiseret støj. Men sikkerheden ligger i opdateringer, stærke legitimationsoplysninger, to-faktor, rate limiting, mindst mulige rettigheder og overvågning på tværs af alle autentificeringskanaler. En hemmelig dør uden de rigtige låse er stadig ikke adgangskontrol.
8. Teknisk appendiks
Yderligere enumeration-kanaler og kontrolfejl, til den tekniske læser. Alle køres uautentificeret mod et eget testmiljø.
oEmbed, feeds og author-sitemap
oEmbed sætter author_name til display_name og author_url til author-URL’en, altså normalt user_nicename. Feeds viser display_name. Author-sitemapet offentliggør author-URL’er med user_nicename. Tallet i wp-sitemap-users-1.xml er sidetallet, ikke en brugeridentifikator.
curl -s "https://ditmiljø/wp-json/oembed/1.0/embed?url=https://ditmiljø/?p=1"
curl -s https://ditmiljø/feed/atom | grep -i author
curl -s https://ditmiljø/wp-sitemap-users-1.xml
Application Password-fejlrespons som orakel
Når mindst én Application Password er oprettet, aktiverer core auth-kanalen. Et ukendt brugernavn giver koden invalid_username. Et gyldigt brugernavn med forkert nøgle giver incorrect_password. Er svarenes code forskellig, kan kanalen bekræfte, om et gættet brugernavn findes. Sikkerhedsplugins kan deaktivere funktionen eller normalisere svaret.
curl -s --user 'wp-test-login-8471:definitely-wrong-8471' https://ditmiljø/wp-json/wp/v2/users/me
curl -s --user 'findes-ikke-935748:definitely-wrong-8471' https://ditmiljø/wp-json/wp/v2/users/me
En korrekt genereret Application Password på 24 tegn kan ikke brute-forces i praksis. De reelle risici er stjålne nøgler, for brede rettigheder, gamle integrationer og manglende rotation.
Alternative ruter til samme endpoint
REST kan tilgås via både /wp-json/ og ?rest_route=. En regel, der kun matcher den synlige sti, lukker ikke fladen. Samme mønster gælder sitemapet, hvor query-formen består, hvis kun XML-filnavnet blokeres.
curl -s 'https://ditmiljø/wp-json/wp/v2/users'
curl -s -G --data-urlencode 'rest_route=/wp/v2/users' 'https://ditmiljø/'
curl -s 'https://ditmiljø/wp-sitemap-users-1.xml'
curl -s -G --data-urlencode 'sitemap=users' --data-urlencode 'paged=1' 'https://ditmiljø/'
En PHP-baseret afregistrering af selve ruten rammer begge URL-former. En ren URL-regel gør ikke.
En uafhængig cybersikkerhedsaudit kan afdække, om jeres WordPress-installationer udleverer brugernavne udefra, om de øvrige autentificeringsflader er lukket, og om konfigurationen matcher jeres sikkerhedspolitik.
Hvornår fik I sidst en uafhængig sikkerhedsgennemgang fra en erfaren ekstern specialist, der tør sige tingene, som de er, i stedet for at sælge jer endnu et plugin?
Har du brug for en gennemgang af jeres WordPress-sikkerhed og autentificeringsflader?
Kontakt Nielco IT på telefon 70 13 63 23 eller via kontaktformularen.



