Ska du stänga av xmlrpc.php i WordPress? Rådet är tio år gammalt
Nej, inte per automatik. Rådet att blockera xmlrpc.php bygger till stor del på en sårbarhet som WordPress täppte till i version 4.4, den 8 december 2015. Filen har alltså varit lagad i tio år, och ändå ärvs rådet oförändrat vidare i den ena härdningslistan efter den andra. Det gör inte xmlrpc.php ofarlig, men det gör den vanligaste motiveringen till att stänga av den föråldrad.
Det underliga är att den kodsnutt nästan alla kopierar för att stänga av filen ändå inte stänger av den enda delen som fortfarande är värd att bry sig om. För att vara säkra på att vi hade rätt gick vi till WordPress egen källkod i stället för att lita på ännu en guide som citerar en annan guide. Filen heter wp-includes/class-wp-xmlrpc-server.php och ligger i varje WordPress-installation, oavsett om du någonsin öppnat den.
Sårbarheten rådet bygger på stängdes för tio år sedan
Berättelsen bakom "stäng av xmlrpc.php" handlar om en metod som heter system.multicall. Före WordPress 4.4 gick det att packa hundratals inloggningsförsök i ett enda anrop till filen, eftersom kärnan prövade varje användarnamn och lösenord i multicall-listan för sig. En angripare kunde alltså testa en lång lista lösenord utan att skicka hundratals separata förfrågningar, vilket gjorde försöken svårare att upptäcka för skydd som räknar förfrågningar.
Den vägen stängdes i metoden login(). Så här ser den relevanta koden ut i dagens kärna.
if ( $this->auth_failed ) {
$user = new WP_Error( 'login_prevented' );
} else {
$user = wp_authenticate( $username, $password );
}
Strax under sätts en flagga, med kärnans egen kommentar kvar i koden.
// Flag that authentication has failed once on this wp_xmlrpc_server instance.
$this->auth_failed = true;
Efter det första misslyckade inloggningsförsöket i samma förfrågan anropas wp_authenticate() aldrig igen. Alla efterföljande anrop i samma system.multicall får svaret login_prevented utan att något lösenord över huvud taget prövas mot databasen. Berättelsen om hundratals gissningar i en enda förfrågan beskriver alltså WordPress 4.3 och äldre, inte den version du kör i dag.
Vi kontrollerade det mot källkoden i respektive version och inte bara mot dagens kod. Söksträngen auth_failed förekommer noll gånger i WordPress 4.3, tre gånger i WordPress 4.4, och exakt samma mekanik finns kvar i kärnan än i dag. Aktuell WordPress-version är 7.0.2. Vill du läsa metoden själv finns den dokumenterad i WordPress egen utvecklarreferens.
Att rådet är föråldrat hindrar det inte från att spridas vidare. Sårbarheten står fortfarande kvar under en egen rubrik, formulerad i presens, i internationella hostingguider som serveras i dag, och kopieras vidare av folk som inte har någon anledning att misstänka att grunden försvann medan de skrev.
Snutten alla kopierar stänger inte av det som faktiskt är kvar
Söker du på hur man stänger av xmlrpc.php hittar du i princip alltid samma rad, oftast rekommenderad för functions.php eller via en säkerhetsplugin.
add_filter( 'xmlrpc_enabled', '__return_false' );
Problemet är att den inte gör det de flesta tror. Kärnans egen dokumentationskommentar (docblock) för filtret xmlrpc_enabled, skriven av utvecklarna själva rakt ovanför koden, säger det rent ut.
"Contrary to the way it's named, this filter does not control whether XML-RPC is fully enabled, rather, it only controls whether XML-RPC methods requiring authentication - such as for publishing purposes - are enabled. Further, the filter does not control whether pingbacks or other custom endpoints that don't require authentication are enabled."
Trots namnet styr filtret alltså inte om XML-RPC är helt påslaget. Det styr bara de metoder som kräver inloggning, till exempel för att publicera inlägg från en extern klient. Pingbacks och andra ändpunkter som inte kräver autentisering ligger kvar precis som förut. Kör du den mest kopierade raden i hela WordPress-ekosystemet stänger du alltså av den autentiserade halvan och låter resten stå öppen. Många som kört den raden tror att de är klara, utan att vara det.
Innan du blir orolig för pingbacken förtjänar den en rimligare beskrivning än den brukar få. Historien om pingback som ett verktyg för överbelastningsangrepp och för att lura servern att hämta interna adresser är från 2014, och kärnan har byggt igen det mesta sedan dess. Hämtningen sker med wp_safe_remote_get(), som vägrar ansluta till privata adressintervall, alltså den funktion som sluter dörren mot serverns eget innanmäte. Vidarebefordringar följs inte alls, eftersom redirection står på noll. Svaret som hämtas hem klipps vid 150 kilobyte, och den ursprungliga besökarens adress skickas med i huvudet X-Pingback-Forwarded-For, så mottagaren kan se varifrån begäran egentligen kom. Ytan finns kvar och det är riktigt att den inte är noll, men den är betydligt smalare än berättelsen om den.
Vill du styra mer finkornigt finns bättre verktyg i samma fil. Filtret xmlrpc_methods låter dig plocka bort enskilda metoder ur listan i stället för allt eller inget, och xmlrpc_element_limit styr hur mycket ett enskilt XML-element i en förfrågan får innehålla. Det sistnämnda är för övrigt redan begränsat i kärnan. Klassen IXR_Message sätter ett tak på 30 000 element sedan WordPress 4.0, filtrerbart via just det filtret. Även utan någon åtgärd från din sida finns det alltså redan ett tak mot orimligt stora nyttolaster.
Kolla på trettio sekunder om din xmlrpc.php ens är nåbar
Innan du bestämmer dig för att göra något alls, ta reda på vad som redan gäller för din sajt.
- Öppna
https://dindoman.se/xmlrpc.phpi webbläsaren, eller körcurl -Imot adressen. - En nåbar standardinstallation svarar 405 med huvudet
Allow: POSToch kroppstexten "XML-RPC server accepts POST requests only." - Får du 403 eller 404 blockerar din server eller ditt webbhotell filen redan, ofta via en regel längre fram i kedjan. Svensk delad hosting kör ofta ModSecurity eller Imunify360, och då kan frågan vara besvarad åt dig utan att du gjort något.
- Även om du satt
xmlrpc_enabledtill falskt fortsätter kärnan att annonsera adressen. Titta i sidhuvudet efter en RSD-länk i stil med<link rel="EditURI" type="application/rsd+xml" title="RSD" href=".../xmlrpc.php?rsd" />. Den ligger kvar oavsett filterinställning, så en skanner som letar efter länken hittar fortfarande att filen finns.
Kör du Jetpack eller appen blockerar du dig själv
Den vanligaste anledningen till att en rakt-av-blockering går sönder på riktigt är att något du använder faktiskt talar XML-RPC. Jetpack kopplar din sajt mot WordPress.com den vägen, och det är ingen kvarleva på väg ut. Jetpacks egen supportsida är tydlig med att ingen sådan övergång har skett.
"If at some point in the future we have to make the transition to the REST API, we will communicate this transition to our users prior to the switch."
Löftet gäller alltså ett framtida byte som ännu inte inträffat. Samma sak gäller WordPress egen mobilapp. WordPress.com har till och med en supportsida på svenska för just det fallet, när webbhotellet blockerar filen. Den säger rakt ut att "för att ansluta en webbplats som drivs på egen server måste XML-RPC-filen vara tillgänglig, så att appen kan kommunicera med webbplatsen". Att sidan finns på svenska säger något i sig. Blockeringen är så pass vanlig hos webbhotell att den behövde ett eget svar.
Har du Jetpack eller appen igång och stänger filen helt, till exempel via .htaccess eller en brandväggsregel som stoppar hela xmlrpc.php i stället för att filtrera metoder, slutar kopplingen att fungera. Kontrollera vad du faktiskt använder innan du stänger dörren.
Den verkliga anledningen till att "max fem försök" inte räcker
Om multicall-hålet stängdes för tio år sedan, varför talar säkerhetsfolk fortfarande om brute force-attacker mot xmlrpc.php? Svaret handlar om hur inloggningsförsök begränsas rent generellt, snarare än om något som är unikt för XML-RPC. De flesta enkla skydd räknar misslyckade försök per IP-adress och blockerar efter ett visst antal. Det fungerar mot en angripare som kör från en maskin. Det fungerar sämre mot ett botnät som sprider försöken över tusentals adresser och roterar dem, eftersom varje enskild adress aldrig kommer i närheten av gränsen. Räkningen stämmer, men den mäter fel sak.
Det finns också en resurssida av saken. Varje anrop mot xmlrpc.php startar en PHP-process precis som vilket annat anrop till en sida som helst, och tar därmed en av de platser ditt webbhotell tilldelat kontot. Tillräckligt många samtidiga förfrågningar pressar alltså mot samma tak som din vanliga trafik konkurrerar om, oavsett om något anrop lyckas logga in. Vi har inte mätt hur ofta det utlöser fel på svensk delad hosting, men mekaniken är densamma som bakom de dolda resursgränser som redan gäller för WordPress-sajter på delade paket. Ett filter som stoppar mönstret innan det når PHP löser båda problemen samtidigt.
Att byta bort "admin" hjälper mindre än du tror
En vanlig sidoåtgärd är att byta administratörens användarnamn från det förutsägbara "admin". Det är inte fel gjort, men det löser mindre än det låter som. WordPress eget REST-gränssnitt kan nämligen lämna ut användarnamn för publicerade konton via /wp-json/wp/v2/users, anonymt och utan inloggning. Den som vill räkna ut giltiga användarnamn behöver alltså sällan gå via xmlrpc.php alls. Byt gärna bort "admin", men lita inte på att det ensamt gör kontot osynligt.
Så avväger du
Väger man ihop det här blir avvägningen tydligare än tio år gamla rubriker antyder. Använder du inte Jetpack, mobilappen eller någon annan integration som talar XML-RPC mot din sajt, är det rimligt att stänga av xmlrpc.php, eller att filtrera bort de metoder du inte behöver via xmlrpc_methods. Det ger mindre brus i loggarna och en mindre yta att hålla ögonen på. Men gör det med rätt förväntan. Du täpper inte till en aktiv sårbarhet. Du städar bort en gammal ingång som redan var stängd för det farligaste den en gång användes till.
Använder du däremot något som är beroende av filen, blockera den inte rakt av. Luta dig hellre mot ett brandväggslager som filtrerar mönster i trafiken än mot en total avstängning som slår ut integrationen tillsammans med det du ville stoppa. Det är den sortens gränsdragning som hör hemma i vår bredare genomgång av webbhotell för WordPress, där skydd på servernivå gör mer nytta än en enskild rad i functions.php.
Misstänker du att sajten redan är komprometterad, oavsett väg in, är nästa steg inte att experimentera med filter utan att gå igenom vår genomgång av sanering efter en hackad WordPress-sajt. Vill du ha den bredare bilden av vad som faktiskt skyddar en WordPress-sajt finns den i vårt svar på hur du skyddar din WordPress-sajt från hackning. Rådet om xmlrpc.php är en liten del av den bilden, och tio år gammalt dessutom.