Du tror dit skjulte WordPress-login er sikkert. Det er det ikke.

Skjult WordPress-login er ikke sikkerhed: luk 9 flader

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

  1. Hvad et skjult login faktisk gør
  2. De tre vigtigste beviser
  3. Derfor byggede vi et plugin
  4. Hvad pluginnet lukker, og hvad det bevidst ikke lukker
  5. Flere flader
  6. Har du allerede Wordfence?
  7. Installation og download
  8. 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

Hent pluginnet (zip)

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.

John Nielsen

Skal jeg kontakte dig?

Eller kontakt os på

+45 70 13 63 23

info@nielcoit.dk

Udfyld formularen - så tager vi en hurtig og uforpligtende snak om, hvordan jeg kan hjælpe.

Seneste på bloggen

Data i Finland er ikke det samme som finsk jurisdiktion

Data i Finland er ikke det samme som finsk jurisdiktion

En finsk AI-tjeneste til jurabranchen markedsføres på europæisk dataopbevaring. Modellen er europæisk. Data ligger i Finland. Ingen træning på brugerens forespørgsler. Det lyder rigtigt. Men da jeg efterprøvede det mod deres egen dokumentation, manglede der ét lag....

Verdens største annoncekoncern bestemmer nu din adblocker.

Verdens største annoncekoncern bestemmer nu din adblocker.

Verdens største annoncekoncern tjener over 200 milliarder dollar om året på reklamer. Fra den 30. juni bestemmer den også, om du må blokere dem i din browser. Sidste flag fjernes Den 30. juni lander version 150 af verdens mest brugte browser. Med den fjernes det...