Hardening WordPress

From IT Wiki
Jump to: navigation, search

File Permissions

Some neat features of WordPress come from allowing various files to be writable by the web server. However, allowing write access to your files is potentially dangerous, particularly in a shared hosting environment.

It is best to lock down your file permissions as much as possible and to loosen those restrictions on the occasions that you need to allow write access, or to create specific folders with less restrictions for the purpose of doing things like uploading files.

Here is one possible permission scheme.

All files should be owned by your user account, and should be writable by you. Any file that needs write access from WordPress should be group-owned by the user account used by the web server.

  • /

The root WordPress directory: all files should be writable only by your user account, except .htaccess if you want WordPress to automatically generate rewrite rules for you.

  • /wp-admin/

The WordPress administration area: all files should be writable only by your user account.

  • /wp-includes/

The bulk of WordPress application logic: all files should be writable only by your user account.

  • /wp-content/

User-supplied content: intended to be completely writable by all users (owner/user, group, and public).

Within /wp-content/ you will find:

  • /wp-content/themes/

Theme files. If you want to use the built-in theme editor, all files need to be group writable. If you do not want to use the built-in theme editor, all files can be writable only by your user account.

  • /wp-content/plugins/

Plugin files: all files should be writable only by your user account.

Other directories that may be present with /wp-content/ should be documented by whichever plugin or theme requires them. Permissions may vary.

Changing file permissions

If you have shell access to your server, you can change file permissions recursively with the following command:

For Directories:

find /path/to/your/wordpress/install/ -type d -exec chmod 755 {} \;

For Files:

find /path/to/your/wordpress/install/ -type f -exec chmod 644 {} \;

Securing wp-includes

A second layer of protection can be added where scripts are generally not intended to be accessed by any user. One way to do that is to block those scripts using mod_rewrite in the .htaccess file.

# Block the include-only files.

RewriteEngine On

RewriteBase /

RewriteRule ^wp-admin/includes/ - [F,L]

RewriteRule !^wp-includes/ - [S=3]

RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]

RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]

RewriteRule ^wp-includes/theme-compat/ - [F,L]


1. BEGIN WordPress

Note that this won't work well on Multisite, as RewriteRule ^wp-includes/[^/]+\.php$ - [F,L] would prevent the ms-files.php file from generating images. Omitting that line will allow the code to work, but offers less security.

Securing wp-config.php

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 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).

If you use a server with .htaccess, you can put this in that file (at the very top) to deny access to anyone surfing for it:


<files wp-config.php>

order allow,deny

deny from all

</files>

Security through obscurity

Security through obscurity is generally an unsound primary strategy. However, there are areas in WordPress where obscuring information might help with security:

1. Rename the administrative account: On a new install you can simply create a new Administrative account and delete the default admin account; or you can just rename the default user name at installation to something other than "Admin". On an existing WordPress install you may rename the existing account in the MySQL command-line client with a command like UPDATE wp_users SET user_login = 'newuser' WHERE user_login = 'admin';, or by using a MySQL frontend like phpMyAdmin.

2. Change the table_prefix: Many published WordPress-specific SQL-injection attacks make the assumption that the table_prefix is wp_, the default. Changing this can block at least some SQL injection attacks. This is for PRE-INSTALL ONLY. Doing this to a live site is advanced work as doing this wrong will kill your site. If your starting with a fresh new install, you have an option during the install screen to change the database prefix. All default WordPress installs use the database prefix of “wp_” which makes any exploiter’s job much easier, change this prefix to something unique.

3. Change your WordPress Nickname. Bots will scrape your sites posts looking for author tags and then use the names it find as your login username, this is a very effective attack vector for guessing through brute force. In your WP admin click your Profile or Users and add a Nickname ( or First Name) and then select “Display name publicly as” something different from your actual login username!

Get some WordPress security keys

WordPress has implemented encrypted security keys for information stored in your cookies.

These keys go into your wp-config.php and you can find a random number key generator on the official wordpress.org site here https://api.wordpress.org/secret-key/1.1/salt/. Hit refresh on your browser to get new keys and copy/paste the whole thing into your wp-config.php.

Limit login attempts

Plugin use for security can be an afterthought, and relying on something to protect what is already insecure is bad practice. The plugin Limit Login Attempts on the other hand is very useful as it prevents too many failed logins to your site and locks out brute force attacks. It can even log IP’s that are failing to get in.

Check your file and directory permissions

File and directory permissions can be tricky depending on the host. In the majority of cases you want to have files set to 644 or 640 and folders set to 755 or 750. You should never have to set anything to .777 unless your host has been mis-configured, EVER! The golden rule with permissions is to set them as low as you can while keeping the site in working order.

Hide version info

Hiding the WP version info is a small step to prevent bots from crawling your site, it does not prevent fingerprinting, but every little bit helps. In your theme’s functions.php add the following:

// remove version info from head and feeds

function complete_version_removal() {

return ;

}

add_filter('the_generator', 'complete_version_removal');

Enable ssl login

Enable ssl login if your site has an ssl certificate. To enable ssl your site must be reachable by using https. You can enable this just for the login or for the whole Admin in your wp-config.php. SSL login will encrypt the data you send to WordPress and is especially helpful to thwart man-in-the-middle attacks.

// this goes in your wp-config.php file

//

//for just the login

define('FORCE_SSL_LOGIN', true);

//for the whole admin

define('FORCE_SSL_ADMIN', true);

Don’t allow search bots to browse your directories

Google search can crawl unwanted urls and expose them to hackers. It’s best to prevent Google bot and any other bots that follow robots.txt (not all of them do) from indexing anything but your content. The robots.txt goes in your site’s root folder and is just a text file.

User-agent: *


Disallow: /feed/

Disallow: /trackback/

Disallow: /wp-admin/

Disallow: /wp-content/

Disallow: /wp-includes/

Disallow: /xmlrpc.php

Disallow: /wp-

Basic .htaccess Rules

Some basic rules that you can add to your root .htaccess file, more advanced rules are covered in the advanced guide as messing around here can break your site, but these won’t do much other than protect you.


//limit indexing of directories

Options All -Indexes


//protect the htaccess file,

//this is done by default with apache config file,

// but you never know.

<files .htaccess>

order allow,deny

deny from all

</files>


//disable the server signature

ServerSignature Off


//limit file uploads to 10mb

LimitRequestBody 10240000

Delete the readme and any unnecessary files

WordPress has a default readme.html, and many plugins and themes also come with one. It’s best to just delete them as they can be used for fingerprinting or general snooping and often contain version info. Also keep your folders clean of any junk files.

Hide your plugins

Adding a blank index.html into your /wp-content/plugins/ folder will hide the contents to anyone who navigates to the /wp-content/plugins folder. They should already be unable to navigate and view this if you have added the "limit indexing of directories" into your .htaccess file. So this might not be necessary if you have done that but it can't hurt.

Restrict database privileges

For MySQL user privileges, the following should be all you need to have for normal day to day activities:

  • Alter
  • Create
  • Delete
  • Insert
  • Select
  • Update

Note: When updating or otherwise changing WordPress, change the privileges to All Privileges, then change back to the limited set above when done.