This article describes a simple method to improve WordPress site security by blocking xmlrpc in Apache Server configuration. Deterring brute force attackers is also great way of saving bandwidth and obtaining more meaningful visitor statistics. Moreover, pages load more quickly as CPU load drops.
In addition to blocking xmlrpc, WordPress users editing their sites offline might consider to also block calls to the wp-admin and wp-login interfaces.
The Xmlrpc Interface
Many WordPress users may not be aware of an innocent little link embedded in their page headers: a call to xmlrpc.php.
<link rel="EditURI"
type="application/rsd+xml"
title="RSD"
href="https://classfactory.com/xmlrpc.php?rsd">
In the early days of WordPress, the xmlrpc interface served as an offline-blogging client for connecting and publishing content[1]. But users editing their site by logging into the wp-admin area probably never needed xmlrpc. And yet, a good chunk of traffic emanating from their WordPress instances may be caused by xmlrpc invocations.
XML stands for extensible markup language and RPC is short for remote procedure call[2]. Fortunately, WordPress’ xmlrpc requires authentication before committing any changes. Under the hood, the tool appears to call PHP code in “class-wp-xmlrpc-server.php”. Without going too far into an analysis attackers are interested in the login function:
/**
* Log user in.
*
* @since 2.8.0
*
* @param string $username User's username.
* @param string $password User's password.
* @return WP_User|false WP_User object if authentication passed, false otherwise
*/
public function login( $username, $password ) {
Regrettably, attackers have an easy game getting user names since WordPress has a function enumerating authors. Try calling the following URL:
https://classfactory.com/?author=1
Though the call delivers a page having a fat “Nothing Found” across, it redirects to this URL:
https://classfactory.com/author/cldev/
Now have a guess which username I picked setting up my site. Also, trying “?author=2” will tell you that the first and only user has admin rights.
Given a user name, attackers are ready to proceed to stage 2: a brute force attempt trying out passwords.
Blocking Xmlrpc
Having concluded that xmlrpc probably won’t work to site owners’ advantage, there are several options of blocking it. The easiest way is to just delete the file “xmlrpc.php” in WordPress’ root directory. However, this method bears the risk of accidentally restoring xmlrpc during maintenance updates. Moreover, attempts at calling the service will redirect to a “Not Found” page still causing server load.
There is a simple and superior way to improve WordPress site security by blocking xmlrpc in Apache Server configuration: just add a redirection command in the site specific setup.
<VirtualHost *:443>
...
redirect permanent /xmlrpc.php https://blackhole.classfactory.com/xmlrpc.php
...
</VirtualHost>
Given this redirect, instead of receiving a service response attackers get an error 301 marked bold in the log line below.
classfactory.com:443 162.158.222.119 - -
[29/Nov/2022:22:01:40 +0100]
"POST //xmlrpc.php HTTP/1.1"
301 613 148 "-" "-"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/89.0.4389.114 Safari/537.36
The error 301 instructs attackers to go looking to blackhole.classfactory.com where xmlrpc.php supposedly moved. And since this subdomain doesn’t exist, literally end up in Nirvana.
Of course, pretty much any redirection target does the trick. It should just be somewhere you control name servers or else other security risks might arise.
Blocking Global Access to wp-admin
Since I’m creating all my content locally on my laptop, I never use the admin interface for my globally accessible WordPress sites. This begs the question why I should keep tolerating brute-force attempts at wp-login.php. Therefore, I added two more lines to my Apache config to improve site security:
<VirtualHost *:443>
...
redirect permanent /wp-login.php https://blackhole.classfactory.com/wp-login.php
redirect permanent /wp-admin https://blackhole.classfactory.com/wp-admin
...
</VirtualHost>
The first redirect kills attempts at hacking passwords and the second any access to the admin interface. Therefore attackers are also blocked from exploiting possible bugs in the admin code.
Alternatively one could configure a temporary redirect omitting the “permanent” keyword in order to have the admin interface available at times. Know that some browsers have a very hard time recovering from permanent redirects!
Site Security Threat Statistics
The trend of daily hacking attempts at my sites is graphed in Figure 1. After answering xmlrpc requests with error 301 in mid August 2022, there was a marked shift from xmlrpc to wp-login attacks. Because of the sheer number of calls, I had to use a logarithmic scale. Days topping 10,000 wp-login attempts may not show the full scale of the problem due to firewall mitigation. Interestingly, also blocking wp-login at November 19 2022 appears to have discouraged xmlrpc calls as well.
Since blocking login options, attackers trying to find login dialogues alternate between xmlrpc and wp-login. This pattern persists all through December and suggests that regular scans originate from very few sources, if not a single one.
Summing up, to effectively reduce server load from attackers one needs to block both the xmlrpc interface and wp-login.
I will be posting updates 🙂
References
[1] What Is xmlrpc.php in WordPress and Why You Should Disable It: Hostinger.com
[2] XML-RPC Interface: WikiPedia.org