How to Harden Your WordPress Site From Attacks
The WordPress Security Learning Center
How to Harden Your WordPress Site From Attacks

1.7: How to Harden Your WordPress Site From Attacks

Intermediate
Updated September 30, 2024

This article is designed to equip you with the beginner to intermediate level knowledge necessary to administer a secure WordPress website. We’re going to cover the most important items to focus on to ensure that your site and data stay secure. This will provide you with solid foundational WordPress security knowledge.

What are you protecting?

Most website administrators think that they’re protecting their website and its files. However, as we’ve seen from major hacks like the Target hack in 2013 (70 million credit cards compromised), your user or customer data is the most important thing you’re protecting. Most of this data lives in your MySQL database, the database that serves as the back-end for WordPress.

First protect your customers’ data. Remember, your customers have entrusted you with their personal information and once you violate that trust by running an insecure website that gets hacked, it’s very difficult to recover. Hacks happen, but it’s your job to reduce the likelihood of getting hacked to the lowest probability possible.

Then protect your website. You are also protecting your website files and these are almost as important. They don’t usually contain sensitive user data, but if an attacker has the ability to read or modify your website files or source code, they can very easily collect user data and can also get the login information for your database that will allow them to directly access your user data. Once your files are compromised you should consider your user data compromised too.

Only Install Trusted Software

This might sound trivially easy, but a common way that websites get infected is by the site administrator installing the infection themselves.

The wonderful thing about the WordPress community is that there are a huge number of open source or free plugins and themes available. There are also a large number of PHP applications besides WordPress available for your website. Unfortunately there are also malicious people who take a perfectly safe and secure plugin or theme and turn it into something malicious. This is called a nulled script.

A nulled script is one where a hacker has taken (for example) a plugin called ACME Plugin and has modified the source code to do something malicious. This might include adding a back-door to give them access to your site, or simply including code to do malicious things like send spam from your site. Nulled scripts are usually distributed from a third party website rather than the original distributor of the plugin or theme. So the hacker will grab working code and distribute it from ‘badsite dot com’ or something similar.

The way to avoid nulled scripts is to only download add-ons for your site from reputable sources. WordPress.org is the most common place plugins and themes for WordPress are found. Commercial plugins or themes can be found at sites like ThemeForest.net or WordPress.com. The following is a list of sites that we trust for plugins and themes:

If you have found what looks like a reputable site distributing an add-on that you need, you might try googling the domain name in quotes to see if anyone is mentioning that site as reputable. You could also download the code and have an experienced developer examine the PHP code for anything malicious.

Updating Core, Themes and Plugins

Keeping your WordPress installation up-to-date is the most important thing you can do to keep your WordPress site secure, as we discussed in the previous article. You can use a product like Wordfence to receive email alerts when a theme, plugin or WordPress core needs an upgrade.

Alternatively, if you sign-in to your WordPress site every day, look at the admin bar which will indicate if you have any updates pending. Some plugins like Wordfence can upgrade themselves automatically when a new version is released, but this is rare. Maintaining your WordPress site with the newest versions and security updates is the most important thing you can do to improve site security.

If you’re using Wordfence on a number of sites, look at using Wordfence Central to make managing updates much easier.

How WordPress Auto-Updates Work

Starting in WordPress 3.7, released back in October 2013, WordPress provided support for auto-updating. In the current version of WordPress, automatic updating of WordPress core is enabled for minor releases and translation files. The reason the security team did this is because most security updates for WordPress are released as minor releases.

However, a little known fact is that the WordPress security team also has the ability to automatically update a plugin on your site in the case of a severe security vulnerability. This is also enabled by default for all current WordPress versions. On April 10, 2014, the WordPress security team used this feature for the first time to do an automatic upgrade of the JetPack plugin when a serious security flaw was discovered.

The WordPress security team does not currently push automatic security updates for themes because the risk is too high. They don’t currently have a way to verify whether a theme file has been edited or if it’s the original distribution and whether an automatic update will damage a site with a customized theme. Pushing a security update that leaves a site broken does nothing to improve security.

We recommend you leave the WordPress automatic update system at its default setting. However, if you’re running a site using version control, you have your own deployment system or if you are a managed host with your own updating system you may want to customize this behavior. Here are a few resources you can use to further understand WordPress auto-updating and how to customize it:

File Permissions and the WordPress Directory Structure

WordPress is a PHP application that runs on a web server. That means that it is a collection of PHP files along with images, HTML and javascript files and other resources. During the normal operation of WordPress, few files change on the website. In fact, for most requests, the only files that will change are log files which exist outside of a WordPress installation.

FileDirectory_1340px

So in theory, to prevent hackers from modifying your PHP code and installing their own malicious code, you can improve security by simply making your PHP files unmodifiable. You can do this by placing restrictive file permissions on your website files. However, this comes with a very serious downside.

When you use file permissions to restrict changes to your website code, it prevents WordPress from upgrading WordPress core files, your plugins and your theme files. That means that automatic security updates for WordPress core and your plugins (discussed above) will be disabled. It also means that you will not be able to upgrade core, themes and plugins via the WordPress web based administration panel.

Restricting your file permissions forces you to manually upgrade your WordPress core, theme and plugin files. This is a very labor intensive process. If you would like to learn more about how to do this you can read our guide on manually upgrading WordPress. This will give you an idea of how labor intensive the process is.

In general we advise our users to not restrict file permissions to a point where the web interface is unable to keep the WordPress installation up-to-date. However if you’d like to learn more about how to restrict file permissions you can view this article. We’ve included several suggested permission schemes and details on how to implement the necessary file ownership and permission changes.

Strong Passwords

Choosing a strong password is important, but for reasons few understand. First, lets look at ways that hackers try to guess your password. Once we understand that, we’ll discuss what makes a strong password and the differences between a strong and weak password.

Strong Passwords to Protect Against Brute-Force Attacks

The most common way a hacker might try to guess your password is by going to the login page on your WordPress site and repeatedly trying to guess your password by entering your username and password and clicking the login button. This is called ‘brute-force hacking’ because there is no art or complexity to it, they’re simply trying to ‘brute’ their way in to your website.

A hacker manually guessing passwords by typing them in might at best make a guess every three seconds if they are on a fast connection and your website is very responsive (and they can type super fast). Most hackers use automated scripts when trying to brute-force a website. This allows them to make many more guesses – up to 10 per second or more. The automated script will repeatedly submit your login form with a different password, and occasionally a different username.

Even using automated scripts, brute-force attacks are relatively unsophisticated. Usually the site administrator’s account is targeted. Hackers will frequently try the ‘admin’ username which was the default administrative user for WordPress for many years. Alternatively they will try to figure out who the site owner is by scanning for post author usernames and they will try to brute-force that account based on the assumption that it has admin level access.

Wordfence and other security products protect against brute-force attacks by limiting the number of guesses you can make per hour. We also protect against ‘author=N’ scans which is the method that hackers use to try to find your admin username.

Brute-force attacks that use the login form are a good reason to use a strong password. Even a moderately strong password will protect against these kinds of attacks. However, there is a reason to use much stronger passwords which we’ll explain next.

Stronger Passwords to Protect Against Password Cracking Attacks

Lets assume for a moment that a hacker has successfully broken into your website and has access to your database. Usually they will install some kind of malware and may download your user data. This is already a worst-case-scenario. In the real world, this kind of thing happens. It is an unfortunate reality. So in addition to securing your website, you need to take action to limit damage in a worst-case like this.

In the older days of the Internet, many websites used to store user passwords as plain-text. If a hacker broke in and stole these passwords, they could use them to gain access to many other websites. For example, if a user has an @gmail.com email address, it would be logical to try the same password they have used on a hacked website on their GMail account to see if you can get access to their email.

WordPress prevents the stealing of passwords by storing your password as a ‘hash’. This is a mathematical signature that can be used to determine if you typed the correct password when you try to sign-in, but cannot be used to reverse engineer the password itself.

Using hashes, security is improved and passwords are no longer stored ‘in the clear’ as plain text. However, cracking programs can use a dictionary to try and generate the same hash that is stored in the database, and if successful, they have reverse engineered your password. For this reason it is important to choose a password that is difficult to guess and is not based on a single word.

Lets look at a few password examples:

  • banana – Very easy to crack because it appears in a dictionary.
  • Banana – Harder, but a cracking program would still guess this in a few seconds
  • Banana1 – Still harder, but hackers often add one upper-case letter and try all numbers appended to your password, so this will also be cracked
  • BananaPear243 – This is very challenging for a password cracker. It may take several days to guess this, but is still feasible to crack because it has a predictable structure and is based on words in the english language.
  • D$%Twr&@8z – This is incredibly hard to crack for a password cracker. They would have to try every combination of passwords up to 10 characters in length and they would have to include letters (upper and lower-case), numbers and symbols. The number of possible combinations tried would be 80 to the power of 10 (80 possible characters with a length of 10) which is a very large number. 10,737,418,240,000,000,000 possible password combinations to be exact.

Important to Note: The reason it is important to use strong passwords on your website and to encourage your site members to use strong passwords is because, if the worst case scenario arises and your site is hacked, it will be much harder for a hacker to crack your password database and potentially cause much wider damage as they try those passwords on other services that your members use. For example, if one of your members has made the mistake of using the same password on your website as they use on Gmail, if the password is strong and your site is hacked, it is much less likely the password will be cracked and their gmail account will also be compromised. By enforcing stronger passwords on your own website, you are helping keep your members and customers safe on the wider Internet.

Only use SSH and SFTP, Never Use Plain Old FTP

When transferring files and administering your website, most admins use FTP or sFTP (also called secure-FTP). Plain old FTP is a very old protocol that dates back to the beginning of the Internet. It does not use any kind of encryption for your login credentials. It also does not encrypt files and so all files are sent over the Network as plain-text.

If you are sitting in a coffee shop or on another public network and logging into your site using plain old FTP, a hacker can very easily grab your website username and password and gain full access to your site.

We’ve included the following video to illustrate how incredibly easy it is to steal usernames and passwords when someone is using FTP to administer their website:

As you can see from the video, it is trivial to grab FTP credentials from a network if the victim is using plain old FTP. Even if you aren’t on a public WiFi system, your traffic passes over the public Internet once it leaves the safety of your office or home. Anyone who has access to any of the networks your traffic transits can view your login information in plain text if you have chosen to use plain old FTP.

So, as a rule, always use sFTP which uses strong encryption to sign-in and perform file transfers and other commands. There are alternatives to sFTP like SCP (secure copy via SSH) and FTPS which uses TLS to provide strong encryption. Most WordPress site admins use sFTP because the system that it relies on, SSH, is already installed on most web servers and sFTP can just use that to communicate with the server.

Securing Your Database

In the majority of configurations, WordPress uses a MySQL database to store it’s data. This data includes your posts, pages, comments and most importantly your user data which includes email addresses and password hashes.

Usually this MySQL database runs on a separate machine and your web server which contains your website files and the WordPress PHP code, talks to the MySQL database over a network link.

It is not usually your responsibility to secure the machine running MySQL. Your hosting provider will do this. The machine running MySQL should not be accessible from the open Internet, only from your site’s web server. It will also limit access from your website to the data and tables belonging to your website.

As a site administrator, your website has unlimited access to the data and tables in your MySQL database. By connecting to the MySQL database, your website can create tables, delete them, read all tables belonging to your website and add or change data.

It is your responsibility to ensure that a hacker is not able to access your MySQL database from your web server.

Protect Your wp-config.php File from Unauthorized Reading

Your WordPress wp-config.php file, which resides in your WordPress root directory, contains your database username and password. It also tells anyone reading that file which machine your database runs on. With these three pieces of information, a hacker can connect to your website database and steal your data or make any changes they like.

For this reason it is very important to prevent anyone on the open Internet from reading the contents of your wp-config.php file. The file lives in a directory that is accessible from the public Internet. The only reason this file is not readable by the whole Internet is because it has a “.php” extension. That means that the web server considers this file PHP code. When someone attempts to access the file from the public Internet your web server will not serve the file’s contents. Instead it will try to execute the file as a PHP application, will fail and usually the user sees a blank page.

As you can see, your database credentials are incredibly close to the public Internet and the only thing that protects them is a web server that is, hopefully, configured to prevent certain files from being accessed as text. It is therefore important to ensure that your web server remains correctly configured and you don’t accidentally allow files with a ‘.php’ extension to be served as text.

Hackers will use various tricks to try and fool your website into serving your wp-config.php file. They may use a vulnerability in a plugin to fool the site into serving the contents of wp-config.php. They may try to upload a backdoor that lets them access .php files as text. In general, as long as your site does not have a security vulnerability, your wp-config.php file will not be accessible using these methods.

Editing your wp-config.php file using a text editor that creates temporary files immediately exposes the contents of wp-config.php to the Internet. For example, if you edit your wp-config.php file with the ‘vim’ text editor on Linux, it creates a file called “.wp-config.php.swp”. Anyone accessing your website at https://example.com/.wp-config.php.swp will be able to download this file and the file contains the contents of the wp-config.php file including your database username and password. To prevent this from happening, avoid editing your files directly on your website.

The following video demonstrates how your wp-config.php contents can be exposed when editing files directly on your website via SSH.




Don’t create a backup of your wp-config.php file without a .php extension. For example, making a copy of the file and calling it wp-config.php.old will expose the file contents to the public Internet.

If you create a ZIP backup of your website and leave that ZIP file in a public directory on your web server, your wp-config.php can be accessed by simply downloading that ZIP, opening it and viewing the file. Password protected ZIP files are easy to crack so don’t rely on this either.

Moving your wp-config.php file above your web root

You can move your wp-config.php to a directory one level higher than the root of your WordPress installation. If your WordPress installation is your web root directory, then this moves your wp-config.php file out of your publicly accessible web directories.

Many consider this a significant security improvement because, if for some reason your PHP interpreter stops working and your web server serves .php files as plain text, the wp-config.php file is not accessible. A PHP interpreter being disabled on a website is something that happens infrequently, so this solution is really solving an “edge case”, or something that rarely happens.

Whether this is a security improvement is hotly debated among WordPress professionals. The advantages are, in the rare case where your PHP interpreter is disabled, your wp-config.php file is not publicly accessible. The disadvantage is that you may have to add the directory above your web root to your PHP’s open_basedir configuration directive. This increases the number of directories that PHP has access to – which also gives an attacker a way to access those directories.

It’s useful to note that the constants defined in wp-config.php which contain your database login, password and hostname can be accessed from anywhere in the WordPress application. So if an attacker is able to execute PHP code in the context of your WordPress application, they can access what is contained in wp-config.php, even if you hide it in a directory above your web root.

At this time we don’t recommend you put wp-config.php in a directory above your web root, because in our opinion, the security benefit is minimal. It is, as we say in the industry, “security through obscurity” or – trying to make things secure by hiding them.

Protect Yourself from SQL Injection Attacks

The other major way that hackers can access your website database is by performing a SQL injection attack. This attack involves sending SQL commands to your database via a vulnerable application that is not properly cleaning and escaping the SQL commands it sends to the database. We’ll cover SQL Injection in more detail later.

Exploiting an SQL Injection attack is very easy. The following demonstration video shows you how easy it is for a hacker to use Kali Linux and SQLMap to download any data in your database that they would like:

As you can see, having a SQL injection vulnerability on your site leaves you wide open to attacks. That is why it is critically important to keep your plugins, themes and WordPress core up-to-date. There are other attacks that target your database less directly, and these all usually stem from vulnerabilities in your website that are exploited.

Protect your Backups

Site backups are frequently not given the respect they deserve. Besides containing all your website files, your site backups also contain an entire dump of your site database. Unfortunately we have seen website administrators that carelessly leave website backups in publicly accessible directories where they are easily downloadable. Be careful not to make the same mistake.

If you are storing your backups off-site – for example if you download them to your workstation or to a USB stick, make sure your workstation or storage media is stored securely.

You May be Legally Liable for Your Stolen Data

In 2006, ChoicePoint was fined $10 million in civil penalties and $5 million in consumer damages by the Federal Trade Commission because they had 160,000 customer records stolen. The data theft resulted in 800 cases of identity theft.

The ChoicePoint case gives you a good idea of how important it is to secure your customer data and how you or your business may be liable for any data stolen and the damage caused by the theft.

Run a HTTPS-only Website

The application protocol that browsers use to talk to web servers is called HTTP and was invented in 1989 by Tim Berners-Lee. HTTP was originally designed as a plain-text protocol. A browser would simply connect to a web server and send the request as text and receive the response as text. Anyone listening on the network could see the conversation.

In 1994, Netscape invented HTTPS which enabled encrypted communication between browser and web server. HTTPS has been used for ecommerce transactions for several decades, but only in the past few years has it been suggested that all communication on the Web should be encrypted.

Most website administrators seem to think that they don’t need HTTPS unless they are performing credit card transactions on their website. The following video demonstrates the need for all WordPress websites to use HTTPS exclusively and to disable HTTP access.

How to Enable HTTPS on WordPress

HTTPS needs to be enabled on your web server. If you are using a WordPress hosting provider, your host will include detailed instructions on how to enable HTTPS on your website. They may require that you buy an SSL ‘certificate’ or they may sell you one themselves or provide them for free. Follow your hosting providers instructions to enable HTTPS.

Note that LetsEncrypt is a non-profit collaboration between major vendors and will be providing free SSL certificates starting in late 2015 and they’re very easy to install.

Once you have HTTPS enabled on your site, you need to configure WordPress to use HTTPS and you need to add a few rules to ensure that your site is only accessible via HTTPS, which will effectively disable plain old HTTP.

Once HTTPS is enabled on your site visit https://www.example.com/ (replace example with your site) and verify that you can see the site via HTTPS.

  • Then sign-into your WordPress administrative interface and go to your WordPress General Settings.
  • Change your “WordPress Address” so that it starts with ‘https://’ instead of ‘https://’
  • Change your “Site Address” so that it starts with ‘https://’ instead of ‘https://’
  • Save the changes.

Now edit your .htaccess file and add the following rule at the top of the file:

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

Replace example.com with your own site URL. This will redirect any request to a regular ‘http’ page to a secure ‘https’ page.

Once you’ve made that change to .htaccess, edit your wp-config.php file and add the following right above the line that says “/* That’s all, stop editing! Happy blogging. */”

define('FORCE_SSL_ADMIN', true);

Save your wp-config.php changes. You should now have a site that only allows access via HTTPS. If anyone tries to visit a page using regular HTTP, they will be redirected to the same page using HTTPS.

At this point it is important that you visit your website and make sure that it is not loading any resources on your secure pages from an insecure URL. In other words, all resources on every page must come from HTTPS websites. It is common on websites that have just upgraded to HTTPS to find several resources like fonts and images that are loaded from insecure pages. Work with your web developer, or address them on a case-by-case basis yourself and point the URL’s to a secure URL instead.

Once you’ve completed changing any insecure resources to their secure version, you should be done and your site should be running HTTPS.

Securing Other Applications, Logs and Files on the Same Server

When you think about your WordPress website, it may help to think about the site as a collection of files that are accessible by anyone on the public Internet. Any file that is in a directory that your web server serves to the public – and that isn’t specifically blocked from public access – is accessible by anyone on the Internet.

When you start thinking about your site in these terms, you start to realize that the following items are all publicly viewable:

  • Backups you have accidentally stored in a web directory. These can be downloaded and include files like wp-config.php which contain your database login credentials.
  • Log files. For example, your web log files and error logs. Your error log in particular contains the structure of your website which can help a hacker gain entry. The error log also occasionally contains login credentials.
  • Other PHP applications on the same site that you may have forgotten about or may not be maintaining.
  • Test files that you forgot to delete. Adding a publicly accessible backup script or another temporary utility script and forgetting to delete it is a common problem.
  • A full copy of your WordPress website that you stored in a directory called ‘/old’ or ‘/backup’. You may not have realized that by doing this you are creating a fully functional new WordPress installation in a subdirectory that also needs to be kept secure and maintained. There are a huge number of unmaintained files in these directory trees that can be used to gain entry if a vulnerability is discovered.
  • Temporary files created by editors like ‘ViM’ that contain the full content of the file being edited. Editing your wp-config.php file directly on your website using ViM creates a .wp-config.php.swp file which contains your database username and password and is downloadable from the Net.

When you view your website directory and the files and subdirectories it contains, you should look at each of those files and make sure you are comfortable with them being accessed by the public Internet.

One of the most common cases we see when a site has been hacked is that the site administrator has been doing a great job of keeping their WordPress site secure. And yet they can’t understand why their site continues to be hacked and their WordPress files are modified by a hacker to inject back-doors. When we examine the rest of the customer’s website, we frequently find a copy of the original WordPress site in a subdirectory that has not been maintained. The hacker has used a vulnerability in one of the old WordPress files to hack into the main WordPress site.

Alternatively we see a different application like phpmyadmin that has not been maintained and has been forgotten about, and this has been used as a doorway in to infect the WordPress site.

Installing a WordPress Firewall

Much of this document is focused on what you can do to secure your site, improve your operational security and help keep your site users and their data secure. We strongly recommend that in addition to securing your site, you should also install a firewall.

In general we believe that a good firewall includes the following features:

  • Malware scanning – The product should include detection for malware installed by a hacker on your website including the ability to see changes and fix them.
  • Brute-force login protection
  • Protection against hacker reconnaissance techniques. For example, protection against the WordPress author=N scan that hackers use to find out your usernames.
  • A full featured WAF or Web Application Firewall with a regularly updated rule-set.
  • Rate based throttling and blocking to prevent aggressive crawlers while ensuring Google’s crawlers have unlimited access to your site
  • Two-factor authentication – the ability to sign-in using your cellphone or another physical device to verify your identity.
  • Password auditing. The product you choose should help you verify you and your site members are using strong passwords.
  • Country blocking – if you are being targeted by a specific country you should be able to block access to various parts of your site or the whole site.
  • Advanced blocking techniques including blocking IP ranges and blocking user-agents.

There are many firewalls available for WordPress. We would encourage you to evaluate several products and to choose one that fits your needs, your budget and your level of technical expertise. Make sure that the product you choose provides excellent customer service and is being actively maintained by the developer.

Using Logs to Detect and Avoid Attacks

Your website logs are a critical source of data and are ignored by most WordPress site administrators until they’re needed. The two most important logs you have available are your website access log and your website error log.

To access these logs you may need to contact your hosting provider and ask them for the location. Note that some hosting environments create multiple error logs in various directories on your website depending on where the error occurred. So ask your host if you only have a single error log or where the rest of your logs are stored.

Your Web Server Access Log

If you are using a security plugin like Wordfence, it includes live traffic that you can view when signed-into your website as administrator. If you don’t have Wordfence installed, you can still view your live traffic by looking at your web server access log.

A typical log entry will look something like this. This example is a log entry from the Apache web server which powers most WordPress websites today.

Web Server Log

When viewing your access log you may see interesting requests that help you debug your website. For example:

::1 - - [12/Sep/2015:06:01:36 +0000] "OPTIONS * HTTP/1.0" 200 126 "-" "Apache/2.4.10 (Ubuntu) (internal dummy connection)"

While writing this article, this request came in. As you can see the request comes from ::1 which is an IPv6 address and it means “myself” or the loopback address. So this is the machine accessing itself. In this case if you google ‘apache ubuntu internal dummy connection’ you’ll learn that this is my Apache web server accessing itself to make sure that it’s own processes stay awake.

Here’s an interesting one:

91.196.50.33 - - [11/Sep/2015:18:58:29 +0000] "GET https://testp1.piwo.pila.pl/testproxy.php HTTP/1.1" 404 457 "-" "Mozilla/5.0 (Windows NT 5.1; rv:32.0) Gecko/20100101 Firefox/31.0"

This is another real request in my logs that came through on the day I wrote this article. The IP is sending a request to my web server trying to probe it to see if my server is running a proxy server. If I was running a proxy, it would mean that they could route requests to any other website via my site. Useful if you want to hide your identity because you are doing some kind of nefarious activity. In this case, they’re trying to get my server to connect to testp1.piwo.pila.pl and a script called testproxy.php which no doubt verifies that a proxy server on my site is working.

As you can see my site returned ‘404’, or “document not found” to the probing server.

Your Web Server Error Log

Your error log often contains a wealth of information for showing attacks on your site. Above we mention that by using Wordfence you can see data similar to your access log in real-time. In fact Wordfence gives you additional data like the geographic location of the IP addresses accessing your site and more. Wordfence does not show you everything in your error log. We only show you page-not-found errors. So it’s important that you monitor your own error log.

A typical entry may look like the following. Note that in our above discussion of the access log, there was an IP address probing for a proxy server. We found a corresponding entry in the error log:

[Fri Sep 11 18:58:29.320573 2015] [:error] [pid 26947] [client 91.196.50.33:60137] script '/var/www/html/testproxy.php' not found or unable to stat

As you can see the page-not-found error was written to the error log. The error log contains much less information than the access log. In general every request to your site will be written to your access log which can make it challenging to filter out malicious entries. Your error log is only written to when a problem occurs, so if you’re looking for malicious activity, start with your error log.

Here’s an interesting entry showing a hack attempt on one of our own websites:

[Fri Sep 11 15:37:43.722390 2015] [:error] [pid 1336] [client 127.0.0.1:43067] PHP Warning:<span class="Apple-converted-space">  </span>session_start(): The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in /usr/local/files/site/wp-content/plugins/someplugin/cptclass.php on line 4, referer: https://example.com/page.html

I have changed some of the data slightly to protect the innocent, but what you’re seeing here is an attacker sending a specially crafted cookie to our site in the hope that they may exploit a vulnerability or trick the site into disclosing some sensitive data. The cookie violates PHP’s cookie conventions and may produce an error with file paths and other useful data. The cookie may also be incorrectly processed by part of the application and may exploit a vulnerability – for example a SQL injection vulnerability if the cookie is stored in a database.

Error logs are a wealth of information and what makes them particularly useful is that they are only written to when something exceptional happens. So we encourage site administrators to regularly check their error logs which will reveal attacks, site misconfiguration and problems with your web applications.

Shared Hosting: Your Hosting Provider’s Responsibilities and Where They End

If you are using a Shared Web Hosting Provider, they will provide you with a fully functional web server and database along with a control panel to manage your website. You will be sharing a single machine with many other customers, but will have your own files and database to host your own website. To your customers, your website appears to be on it’s own web server with it’s own dedicated domain.

If you are using shared hosting, which is the most popular and lowest cost form of hosting ($1 to $10 per month), this section will give you an idea of your hosting provider’s responsibilities with regards to security, where they end and where yours begin.

ResponsibilityBreakdown_1340px

Your Web Hosting Provider is Responsible for the Following items:

Web hosting involves a lot of physical and virtual components. The best way to think about web hosting is to use a metaphor similar to the OSI model. This starts at the physical network layer and works it’s way up to the web application. So, starting at the bottom, closest to the network and physical network cabling, your hosting provider is responsible for:

  • Network cabling
  • Network Routers and their security. If your site is the target of a DDoS attack for example, your web host will use DDoS mitigation, which uses routing as part of the filtering process to stop the attack.
  • Switches – the switches on your server’s network can be accessed remotely and your host will secure these.
  • Cooling and power
  • Physical security of your data, website and any backups of your data.
  • The physical machines your website runs on including power supply, hard drives, memory, CPU, disk controllers etc.

The important thing to note above when discussing security is that your web host is responsible for the physical security of your website. They usually provide biometric (fingerprint or retinal scan) security that someone entering the data center has to pass. Our own data center uses fingerprint scanning along with other non-biometric mechanisms for authentication before you can access our physical servers.

Moving up from the physical hardware and network, your host is also responsible for:

  • The host operating system on each physical server including securing that host operating system
  • The various virtual machines that run on the physical machine that hosts your website, including the security of those virtual machines. Most hosting providers use virtualization and will have many virtual machines running on a host operating system.
  • If multiple users are hosting websites per virtual machine, it is your web host’s responsibility to prevent users from accessing or modifying each other’s data. Usually file permissions and user privileges and ownership will be used to create and maintain separation between users. Hosting plans that offer your own virtual machine are common and slightly more expensive ($10 to $20 per month), while the cheaper plans have multiple users sharing a single virtual machine using ‘virtual hosting’.
  • The physical machine that your database runs on and logical security within the database. Your host will make sure that you have your own username and password to access the database and other customers can’t read or modify your data.
  • The web server that hosts your website including the security and encryption level of your SSL web server. You may have to take action to install the correct SSL certificates for your web server, but your hosting provider needs to ensure that the server is configured to provide a secure level of encryption to web browsers.
  • Your host is also responsible for any other server applications which may include applications like Node.js and Redis.

If your website is hacked, your host can often help with some of the following items. Note that terms and conditions vary between hosts, so find out what level of support your host offers.

  • Detecting a hack. Hosting providers frequently run malware detection scans on their own customer’s files and can alert you to an intrusion.
  • Repairing a hack. Hosting providers may completely repair a hacked website for you or may offer no support, or some support, depending on their level of service. Price usually dictates how much help you will get when your site is hacked and the more expensive hosting providers offer a higher level of support.

Your hosting provider is not usually responsible for the following

Note that some expensive hosting providers may offer some of the following services, but in general the $1 to $10 per month shared hosting providers are not responsible and do not offer help with the following. The following items are your responsibility:

  • Ensuring applications you install are secure. Don’t install nulled scripts.
  • Ensuring your database credentials (username and password) stay secure and aren’t available to the public.
  • Keeping your themes, plugins and WordPress core up-to-date. If a new vulnerability is announced and a fix is released, it is your responsibility to install the fix. In some cases we have seen some large low-cost hosting providers perform a forced upgrade on large numbers of customers affected by a serious vulnerability, but this is not the norm.
  • Installing a web application based Firewall like Wordfence. Your hosting provider can’t usually predict which applications you are going to install and so they don’t usually offer an application specific Firewall.
  • Scanning your site source code for unauthorized changes. There is a wide array of applications available for websites. Your host does not maintain a copy of all available source code to verify yours against. Wordfence does maintain a copy of every version of every theme, plugin and core file ever released on wordpress.org, so we can provide you with this level of source code verification.
  • Providing brute-force login protection for your website. Websites run different publishing systems (WordPress vs Drupal vs Joomla) and other applications like phpmyadmin. Each has their own login screen and authentication mechanism. It is not practical for a host to scan your hosting account for applications that require login and try to secure them all.
  • Provide two factor authentication for your website or other more secure login mechanisms.

As you can see the general theme above is that you are responsible for the security of your website and the data within your database. Your hosting provider takes care of everything below that layer. To that end, you need to ensure all code you are running is secure, your login credentials are kept safe, you use strong passwords and any source code or information that needs to stay private is kept private.

If you do run into a security problem, it is always worth contacting your hosting provider for help. Even low cost providers will frequently give you some level of support, particularly if your problem may impact other customers or their other customers may have the same problem.

Securing your Self-Hosted Linux Server

This section assumes that you are familiar with SSH and are using a Debian variant of Linux like Ubuntu. We’re assuming you’ve opened a terminal session into your linux machine and are comfortable entering shell commands. We provide several shell commands below that help you determine which services are running and to secure your Linux machine.

Self-hosting WordPress on your own virtual machine is more complicated than using a hosting provider, but it comes with some distinct advantages. You can monitor the performance of your own virtual machine. You can completely customize your website configuration – when we host a WordPress site on Linode, we like to put Nginx in front of Apache which gives us better performance.

When you self-host, you are responsible for the security of your own virtual machine and all of the services that run on it. We’ve included a few tips below that will help you secure your Linux machine and your WordPress website.

Check your Services

Once you have your WordPress site up and running, the first thing you should do is check which services are accessible on your machine from the Net. You can do this by running the following command from the Linux command prompt:

netstat -aptn|grep LISTEN

Netstat with these parameters will list all TCP connections on your machine. When you pipe it to grep as above, you’ll only see services that are listening for new connections. This is a great way to see what services are available for someone on the Internet to connect to and to try and hack into your server.

Note that in our examples below we run netstat as root. If you are not signed in as root (which you probably aren’t), we recommend you run netstat using the sudo command. e.g. ‘sudo netstat -aptn|grep LISTEN’

Running netstat with root permissions ensures that you can see the process ID and name associated with any port. You won’t see this otherwise.

Here is an example of Netstat’s output:

Screen Shot 2015-09-12 at 7.41.57 PM

You are concerned with the IP address and port pairs listed.

  • You can safely ignore anything that starts with 127.0.0.1 because it is only accessible from the local machine.
  • You should be concerned about any service listening on 0.0.0.0 because that means “all interfaces” and it is publicly accessible.
  • You should be concerned about IP address/port entries that look like :::80 because those are publicly accessible. The three colons also means “all interfaces” in IPv6 parlance.
  • You should be concerned about any services listening on a numeric IP address like 69.46.36.6:80 because that is your external network card – also publicly accessible.

So in the case above, we know 127.0.0.1:3306 is MySQL and it’s only accessible from the machine itself which is great news. No worry there.

0.0.0.0:22 is a concern because it’s publicly accessible, but we know that is our SSH service and that is secure.

:::80 is our web server listening on port 80 for HTTP requests which is fine. We’re running Apache2 as we can see.

You may also see 0.0.0.0:443 which would be your HTTPS server and that’s fine too provided you expected to run an HTTPS server.

If you encounter entries that have a port number you don’t recognize, you can use this page to look up the port number and determine which service it belongs to. If you don’t recognize that service, investigate further. You should see a process name listed on the far right associated with the port number. Google the process name if you don’t recognize it. Try telnetting to the port to see what response you get e.g. telnet localhost 8888

As you can see netstat is a great way to do a sanity check of what servers your server is actually running. Services you don’t want public should not be listening on 0.0.0.0 or ::: or a public IP address. If you find any, change the service configuration to make sure it’s only accessible from the machine itself.

Upgrade everything and keep it up-to-date

Vulnerabilities emerge for Linux all the time, just as they do with WordPress. Make sure you run:

apt-get update
apt-get upgrade (or instead of upgrade you can use dist-upgrade or full-upgrade.)  

Learn more about dist_upgrade here.

You can also use a package called ‘unattended-upgrades’ to automatically keep your Ubuntu server up-to-date.

The commands above are specific to Ubuntu Linux. If you are running RedHat or Fedora you can simply type:

yum check-update

and

yum update

To update all your packages. You can learn more about how to update RedHat systems on this page.

If you are not using unattended upgrades or another automatic updating system, we recommend that you sign into your Linux machine at least once a week and manually update everything.

Protect SSH from brute-force attacks

One of my favorite tools for Linux servers is fail2ban. It is a brute force protection tool that blocks any IP address that fails login too many times. Installing it is incredibly easy (don’t type the text in parentheses):

apt-get update (to update your apt database)
apt-get install fail2ban

That’s it. That will install and activate fail2ban and you have instant brute-force protection.

Install a Firewall

Installing a firewall on a publicly accessible Linux server is usually a good idea. It prevents you from accidentally installing a new service that is publicly accessible. It also prevents certain kinds of attacks. However, a firewall can slow down performance on a very busy server or a server that has many concurrent network connections.

A firewall on your Linux server can also give you a false sense of security. For example if you have a firewall but are running a vulnerable version of SSH and have allowed connections to SSH port 22, the firewall won’t protect you.

There are several firewall products to choose from for Linux. Here are a few, and because Ubuntu is very popular and we use it ourselves, I’ve included firewalls that are mostly relevant to Ubuntu Linux:

  • UFW Firewall, also called Uncomplicated Firewall, is an easy to configure firewall for Linux. It uses iptables to implement the actual firewall rules and has a graphical interface called Gufw.
  • Shorewall is a firewall that we use for several servers. It is not especially easy to configure, but is a more user-friendly front-end to iptables and has many useful features. You can find the Shorewall Quick-Start Guide here.
  • IPTables is the command line tool that is used to implement most firewall rules. Shorewall and UFW and other firewall products use iptables internally for their rules. You can implement iptables rules yourself if you prefer. You can learn more about how to use iptables on Ubuntu Linux using the Ubuntu HowTo guide. If you are using CentOS or RedHat, this guide will get you started with iptables.

Avoid Plain-Text Logins

Don’t install any services that allow logins that are unencrypted, or plain-text. This includes FTP that uses plain-text login (port 21), telnet (port 23), POP (port 110) or any other service where usernames and passwords are sent over the network as plain-text.

In General

Limit the number of services you run on your machine to the absolute minimum. Limit the number of user accounts and users who have access to the least number.

Make sure that your distribution of Linux stays current. If you don’t frequently upgrade to the next release, you may find yourself using an “end of life” version of Linux which becomes more difficult to upgrade and may not receive important security updates. You can upgrade Ubuntu by running the “do-release-upgrade” command on the command line.

You can check if any files have changed on your Linux machine in the past 24 hours by running the following command:

find /usr -mtime -1 -ls

You can change /usr to /home or /root depending on where you want to search for modified files. This may help you find malicious activity.

Carefully investigate any unusual network, disk or CPU load on the server. If you are using a service like Linode, they provide you with a set of charts that lets you monitor load and will even alert you to unusual load via email.

Securing your own Linux machine is a big responsibility which you can easily delegate to a hosting provider. But the benefits you gain in customizing your own configuration are significant. It’s also a lot of fun!

Fake Security: Things to Avoid

Don’t Password Protect /wp-admin/

One of the common mistakes we see is WordPress administrators who try to protect their administrative area by password protecting the /wp-admin/ directory. Specifically, administrators will place a .htaccess file in the /wp-admin/ directory that cause the web server to prompt anyone trying to access that directory with a “basic authentication prompt”.

A basic authentication prompt is a simple form of authentication that causes the browser to pop-up a dialog asking for a username and password. It is very easy to implement by adding a few lines to a .htaccess file.

The problem with password protecting your /wp-admin/ directory is that your regular site visitors need to be able to access that directory too. The AJAX handler for WordPress lives in that directory at /wp-admin/admin-ajax.php. While this may look like something that is only accessed by admins, it is badly named and is accessed by any feature in WordPress that requires AJAX functionality.

If you password protect /wp-admin/ you will break functionality on your site and your normal site visitors may see the basic authentication dialog popping up in their browsers. Don’t do it.

Don’t Change your Database Table Prefix

There is an urban legend that by changing your database table prefix you will prevent certain kinds of attacks. This is completely incorrect.

There is a command available in MySQL called “show tables;” which shows all tables. Any bot or human hacker will call ‘show tables’ before trying to access your database tables and will immediately see what your database table prefix is and use that when referencing your tables in an attack.

The default table prefix in WordPress is ‘wp_’. Most hosting providers change this to something else when your site is configured. So it is likely that your table prefix has already been changed and installing a plugin or script that changes your table prefix again is pointless and an unnecessary risk to your database tables.

Conclusion

WordPress security involves a learning curve, an initial setup where you configure a secure website and then ongoing maintenance activities as you maintain a secure website. We hope this guide has provided you with and excellent foundation in your WordPress security knowledge and given you specific guidance on how to configure a new secure WordPress website and what you need to do to maintain that website.

We’ll leave you with the three fundamental principles of security:

  • Availability – You need to ensure your site is available at all times. That means you need to ensure it stays performant and can repel denial of service attacks.
  • Integrity – You need to make sure that your database is not corrupt, only your publishers can add content to your site and your website files are not corrupt and don’t contain malware.
  • Confidentiality – You need to make sure that your private data, source code and usernames and passwords remain confidential and are not accessible to hackers or anyone else who should not have access.

AICTriad_1340px

The AIC triad (availability, integrity and confidentiality) is a great way to evaluate your security posture and to remind you what your objectives are. Good luck and stay secure!

Did you enjoy this post? Share it!

The WordPress Security Learning Center

From WordPress security fundamentals to expert developer resources, this learning center is meant for every skill level. Get serious about WordPress Security, start right here.