Last updated on August 17, 2018
Lets be clear about somethings. Security is hard. Even the so called experts get it wrong, surprisingly often at that. I’m not an expert, and I’m not proposing that I’m right. Take what I say with a grain of salt.
In part of WordPress’s hardening guide they discuss moving the WordPress config file (wp-config.php) out of the document root as a mechanism that can be used to make it more difficult to attack. Specifically they say:
You can move the wp-config.php file to the directory above your WordPress install. This means for a site installed in the root of your webspace, you can store wp-config.php outside the web-root folder.
- Note: Some people assert that moving wp-config.php has minimal security benefits and, if not done carefully, may actually introduce serious vulnerabilities. Others disagree.
Note that wp-config.php can be stored ONE directory level above the WordPress (where wp-includes resides) installation. Also, make sure that only you (and the web server) can read this file (it generally means a 400 or 440 permission).
The linked discussion on the topic on Stack Exchange is also worth reading while you’re at it.
With that said, I’m going to throw my 2-cents in to the discussion.
To start with I think it’s important to realize just what this change brings to the table.
Moving the wp-config.php doesn’t make it inaccessible to an attacker. It only makes it difficult or impossible under certain erroneous configurations for an attacker to easily get it.
Specifically two conditions must be met for the file’s contents to be served to an attacker.
- The HTTP server must not be configured to invoke the PHP interpreter for PHP files (i.e. it serves PHP files as text files).
- The HTTP server must not be configured to block access to the file outright.
How much of a concern these two factors are is going to vary from environment to environment. Obviously, more layers of protection is better. I’ve always configured my http servers to deny access to wp-config.php as a matter of course.
By having the default deny rule for the wp-config file, there is at least a secondary layer of protection in the event the PHP hand off is removed.
- Under optimal conditions the wp-config file is parsed by php and nothing is returned even if called directly.
- If the http server is misconfigured and doesn’t hand off to PHP, access to wp-config.php is blocked by the HTTP server’s config.
- Finally by having wp-config outside of the www-root, a misconfiguration bypassing or missing point 2 — which becomes redundant too — the wp-config file is still inaccessible.
That said, I wouldn’t call any of this really security oriented. Yes, there’s protection, but the majority of the protection is against mis-configuration. And while this is all good, more layers of redundancy have their trade-offs in management.
If your server is serving multiple WordPress sites and isn’t using the multi-site support, then it’s necessary to have an additional layer of directories to separate the wp-configs. Moreover, while this can almost always be configured manually, the default by many hosting providers is to create a directory in your home directory for the domain, and make that the domain’s www-root. That means that adding an additional layer involved some more management overhead.
My problem, is that while this arrangement deals with some potential attack mechansims, it doesn’t deal with all of them. And in fact, based on my server logs, I’d say that WordPress users as a whole do a good enough job in protecting wp-config.php that most of the automated attack scripts don’t attempt to get it directly.
Instead, the attack vector appears to be largely targeting vulnerable plugins and themes that have downloader scripts as part of them.
It these kinds of attacks, it simply doesn’t matter what protections are in place at the http server level to prevent reading the wp-config.php file. PHP can read it, which means PHP can send it’s contents to an attacker.
If PHP can read the file, and it has to be able to in order for WordPress to operate, then the file can be read by a poorly written plugin or theme and subsequently sent to the attacker that way.
This is also a somewhat more difficult problem to address, as there several potential avenues that can be plied depending on how the poorly written plugin was configured.
Part of the problem, as I see it, is that PHP doesn’t provide a mechanism to protect configuration files from basic access while still being able to parse them for configuration purposes. There’s no process-xor-read/write flag that tells the PHP environment that a given file can be compiled/interpreted but cannot be accessed using the normal file system APIs.
If the PHP process can read it, meaning it’s in the allowed chroot jail, or open_basedir, for the PHP process — and it has to be or WordPress cannot load it and therefore won’t run — then it can be downloaded by an attacker via this technique.
There’s also the potential that a really poorly written plugin/theme might make it possible for the attacker to gain the contents of the wp-config file via shell function calls (i.e. “less ../../../wp-config.php”). Though this whole aspect should be mitigated by disabling those functions in general as part of generally hardening a PHP install — though this is also a discussion for another time.
Now a sharp eyed reader might notice that the attacks I illustrated above all focus on the wp-config file being in the default location. That’s true. It’s also true that moving it up a directory would mitigate those attacks at least until the attackers started probing the alternate location as well.
Also keep in mind, this is really just more security through obscurity. Some attacks may have been mitigated, but the attack vector hasn’t been closed. Putting the wp-config file 1 directory higher is an officially supported configuration, which means it’s a clear and obvious place for an attacker to look too. The only reason that it’s not being done now is likely because so few sites use that configuration that it’s not worth the added time and requests.
What is actually needed is a way to close the attack vector completely, and that’s where things get tricky.
The most practical solution as things currently stand is a web application firewall (WAF). But it should be one that doesn’t rely on WordPress’ environment — so none of the WordPress WAF plugins really apply.
The reason for this is that it’s simply impossible to assume that a script that’s reading from the file system to serve up content, is going to necessarily instantiate the entire WordPress environment to do so. Most likely will, but that’s just hoping again.
Unfortunately, inspecting query strings isn’t the domain of typical web servers. Nginx can do it kind of, if you use if blocks, but doing so is far from ideal and strongly discouraged. There are WAF plugins for Nginx that can do this very effectively, but obviously adding one adds additional overhead to your management of the site and install. As far as I know, the situation is relatively similar for Apache.
Obviously not running plugins that are vulnerable is a solution, but it’s not a general purpose solution as you never really know what plugin may or may not be vulnerable without extensively auditing the plugin’s code base yourself.
So with all this said, in summary.
- Moving the wp-config file offers some protection against http server misconfigurations
- This may be more or less important depending on the way your host or provider manages things. Does/Can changing a setting in your config panel cause your server to be reset to not running PHP?
- Most current attacks don’t appear to be trying to get the wp-config file from the http server anymore, instead they’re using vulnerable plugins to download the file bypassing any restrictions that might be in place at the http server level.
- Basic protections should still be used.
- Most current attacks still appear to assume the wp-config file is in the default location, moving it provides a temporary amount of mitigation but it should not be relied on as a perminate solution.
- The most effective mitigation to completely prevent an attacker from downloading the wp-config file is some form of web application firewall that isn’t dependent on WordPress’s environment
- Running a WordPress WAF plugin will provide a significant degree of protection presuming the vulnerable plugins actually initialize the WordPress environment in their download scripts.
So is it worth moving wp-config.php?
If you’re setup in such a way that you can deal with the change without it adding much in the way of administrative overhead. Then I don’t see it hurting.
On the other hand, I’m really not convinced that it properly mitigates any actual attack vectors that it’s worth it in and of itself. You still need several additional layers of protection to keep it from being snagged by a vulnerable plugin, and those add further administrative overhead.