Hardening Wordpress

August 25, 2013 Comments

This blog was previously run using Wordpress. Wordpress does not have the best record for having bug free software. To make sure esev.com doesn't get overrun by viruses, I've taken a few additional steps to secure the site. All these steps follow the simple idea that, if it isn't needed for an average viewer of the blog, disable it.

1. Allow only http GET requests
Most of the changes to a Wordpress blog happen with POST requests. By limiting the server to only servicing GET requests, very few modifications can be made to the blog. Of course, this means that none of the administration functions work. More on that in a bit.

2. Deny access to the administration pages
Most of the administration pages are stored in the wp-admin directory. These administration pages allow the blog owner to create new blog posts, add plugins, and customize the site. By denying access to the administration pages, nobody can use those pages to make changes to the blog.

3. Deny access to the login page
Again, if nobody can login to the blog, it'll make it much harder for anyone to make changes to the blog.

4. Use an external comment system
The built-in comment system requires use of http POST requests. Those were disabled by #1. Using the built-in comment system can lead to a lot comment spam to. Use a comment provider, like Discus or IntenseDebate and you'll be handing off the spam filtering to them.

With the blog locked down tightly using the above recommendations, it becomes hard to make any changes, even for the blog's administrator. To allow an admin to access the blog, configure the web server to require SSL and http digest authentication for any action that could modify the blog.

To configure this for Apache, first setup the digest authentication:

    AuthType Digest
    AuthName "esev"
    AuthDigestDomain /blog/wp-admin/
    AuthDigestProvider file
    AuthUserFile /path/to/htdigest.password/file

Then configure the additional restrictions. To limit the web server to only accepting GET requests add this:

    <LocationMatch "^/(?!(blog/(wp-cron|index)\.php))">
    <LimitExcept GET>
            Require valid-user
    </LimitExcept>
    </LocationMatch>

If a request for a request, other than a GET, arrives at the web server, the client is presented with a http digest authentication dialog. Without the proper username or password, these requests will be denied.

Access to all of the administration pages should be denied. The following configuration section for Apache takes care of this, and allows the blog administrator to bypass the restrictions by logging in.

    <LocationMatch "^/+(blog/+(wp-login\.php|wp-admin)|$))">
        Require valid-user
    </LocationMatch>

Sure, the http authentication dialog box looks a bit ugly, but it prevents anyone without the proper user and password from accessing any content that isn't needed. Alternatively, something like mod_auth_cookie_mysql could provide a nice login interface for the administrator.

I don't think this is a bullet-proof way to keep a Wordpress site safe, but it should prevent any automated tools from hijacking your blog.

Categories: Uncategorized