A core feature of WordPress is its built-in Firewall. It is powerful and yet often overlooked. So, let’s take a closer look at it.
It is a reality that many, if not the majority of WordPress plugins, come in several flavours: a free version with a limited set of functionality, and a commercial, a pro version that has to be purchased from the plugin author.
While there’s nothing wrong with that by itself, as a consequence, plugin authors usually need to add additional logic to their plugins that allows them to verify if your current installation has the necessary license or not. And if it does, it will check if it is valid for the current domain, if it’s due for renewal. And so on and so forth…
The caveat here is, that all of these checks are done over the internet, and they are usually done when the plugin is initialised. So when does WordPress initilise plugins? Correct, upon each and every request made to the site. I am not saying that all plugins do this, but some do. Most store the license info into the wp_options table, after the first run. Afterwards they might not even need the permission to make further HTTP connections.
A different scenario where a plugin might establish HTTP connections somewhere is when it has additional dependencies like GeoIP databases, or when it uses some sort of cloud service, like I have seen it with image compression plugins, that instead of compressing the image locally, they send it to a service which does the actual compression and then just receive the compressed file. Such an approach might make sense where users cannot install the necessary PHP extensions like Imagemagick, Gmagick, or others – but especially in a professional environment this is a waste of bandwidth, and it’s sole purpose is to incentivise users to buy a Pro-license.
There’s also wanted communication with the outside world, for example when you install payment gateway plugins, of course you want the plugin to be able to communicate with the providers’ API for example to charge a credit card. In Ecommerce you might have other plugins to pre-check a customers credit score. Or when you use an external email provider to send transactional emails, of course you want WordPress to being able to connect to their servers and send the email.
The same thing happens when you turn on auto updates for plugins (which I would highly discourage you to do) or when you manually update the WordPress core or a plugin in the WordPress backend (which, again, I would discourage to do), WordPress will connect over HTTP to its website and check for new releases or to download packages.
Long story short, there’s wanted, unwanted, and even unnecessary connections that your WordPress installation might be doing with the outside world (wide web).
And this is where you need to investigate the traffic that is being sent from your site – which will allow you to determine which requests are required, and which ones are unnecessary for your site visitors to wait for.
Analyse and monitor connections
Not only the amount of requests is interesting here, also the time it takes for external services to respond. An APM like New Relic can help you a lot to visualise and monitor the specifics.
On the command line you can use this simple logging to see where your site connects to (this does include your site visitors ISPs)
sudo tcpdump dst port 443 # for HTTPS
sudo tcpdump dst port 80 # for HTTP
The good news
There is a quick and easy and effective solution.
defined('WP_HTTP_BLOCK_EXTERNAL') or define('WP_HTTP_BLOCK_EXTERNAL', true); defined('WP_ACCESSIBLE_HOSTS') or define('WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,*.api.mailchimp.com,www.paypal.com');
The first line activates the WordPress Firewall and the second line defines all the exceptions – the sites that you want WordPress to be able to communicate with. So now you are in control. You disallow all external domains and then specify the domains you want to allow.
Keep in mind, that activating the Firewall might break certain functionality, so at the time of activating the firewall, you should already have a list of mandatory domains of accessible hosts.
Limitations of the WordPress Firewall
This article wouldn’t be complete without talking about the limitations of the WordPress Firewall. While the WordPress Core is respecting the Firewall setting – Plugins don’t necessarily do this. Only the WordPress core functions for remote requests
wp_remote_post (and other
wp_remote_* functions that can be found in the file
wp-includes/http.php) respect the setting you made in the wp-config.php.
But PHP offers many more ways to do HTTP requests, such as
cURL and more. Plugins might also use composer packages such as Guzzle – which hints at a plugin establishing HTTP connections. Other plugins use scheduled actions to do those requests in a regular fashion.
So plugins, that use the WordPress core functions for making remote requests will respect the settings you make in your wp-config.php. Chances are they don’t work as expected. Plugins that use one of the mentioned PHP functions or packages are exempt from that rule. In both cases, it is advisable to dig deep into the plugins code and try to understand what the plugin is doing. There’s no general here. It really depends on what a plugin does, and if a 3-4 sec HTTP request is justified.
In many cases, it will be necessary to tweak the plugins code. Maybe commenting out some lines of code. Or make sure the plugin authenticates its license once and after that activate the firewall. Using an editor or IDE you should be able to search through your plugin directories files for terms such as “curl”, “file_get_contents”, “http”, “https”, “guzzle” and more to spot most places where a plugin makes an external connection.
As mentioned before, New Relic (even in a free version) can be helpful to analyse what’s happening under the hood. Also there are standalone Applications like Charles Web-Debugging Proxy that help you to monitor and understand HTTP connections made from your server. I can highly recommend both tools.
Continue reading part 16 of my tutorial series: Deactivate automatic updates.