WordPress Security Fundamentals: How to Not Get Hacked

WordPress has made great strides in its effort to democratize publishing, making the ability to publish content on the web accessible to a very large number of people all over the world. Today, it powers roughly 28% of the websites on the web making it the most widely used platform in the world by far in terms of market share. However, with the status of being number one comes the attention of those who wish to exploit it.

In this article, we’ll look at what you can do to make your site more secure to weather the eternal storm of bad guys.

Isn’t WordPress Secure Already?

Just as it is not possible to secure your home 100%, no site is 100% secure. Every lock has a key which is possible to open by anyone who has something that fits the same way. That is not to say that WordPress is not secure though. As an open-source project with literally thousands of developers working on it, in it, and around it all the time, the collective effort of so many people makes it very strong because it only takes one person to find a vulnerability and report it. WordPress also has a dedicated security team responsible for making sure WordPress core is as secure as possible.

The WordPress Security Team is made up of approximately 50 experts including lead developers and security researchers — about half are employees of Automattic (makers of WordPress.com, the earliest and largest WordPress hosting platform on the web), and a number work in the web security field. The team consults with well-known and trusted security researchers and hosting companies.
https://wordpress.org/about/security/

WordPress core is only one component of the complex system that makes up your website. The majority of WordPress sites are much more than a bare WordPress install. Most plugins and themes, both free and premium do not get nearly the same level of attention, let alone purely auditing for vulnerabilities. If it can happen to some of the largest and well-supported plugins such as Jetpack and WooCommerce, the possibility of concocting a site which has some vulnerability is almost inevitable.

Meet Your Opponents

If we’re going to protect ourselves, it’s important to know what we’re up against to best orient ourselves for success. Where are these attacks coming from? The good news is that the vast majority of attacks are completely automated and not very sophisticated. Much like a search engine which crawls your site for content to index, most attacks start as simple bots which crawl your site looking for known vulnerabilities which are then exploited in an automated way.

Another common source of attacks is from other sites which are already compromised. Think zombie apocalypse. This could be in the form of another site on the same host which tries to reach other sites on the same server, or even in the form of a “botnet” which a swarm of hundreds or even thousands of compromised machines which could be used together to be used in a very powerful way.

Contrary to what you may think, the least common attacker is from an actual human. This is the hardest to protect against as a human can execute a much more intelligent attack, from vectors which are otherwise not possible by a machine (like pick up the phone and call you). The chances of being the target of a human cyber attack are quite low due to the sheer ratio of sites to hackers. Higher profile sites are generally at higher risk as they are of more interest to humans than a blog about cat-shaped knitting templates.

By following the tips in this article you will be poised to be stronger against attacks from all sources.

Keep Everything Up-To-Date

Perhaps the most obvious and easy to do (as well as neglect) would be keeping WordPress core, and all installed plugins and themes updated to the latest stable versions. As a well-known platform, there are large, publicly available databases of known vulnerabilities for WordPress core, plugins, and themes. If your site uses older versions of any software, you are essentially gambling that an attacker does not come and find it.

In addition to keeping your software up-to-date, you can easily further harden your site by hiding the version numbers which are installed.

The two most important pieces of data an attacker can find out about your site in order to compromise it are: what software it is using (WordPress in this case, and which extensions are installed), and what versions they are. Given these bits of information, attackers can be extremely efficient in compromising your site. All they need to do is look up what you have in their playbook, and find the best exploit available to compromise your system with sniper-like accuracy.

Hiding the fact that you’re using WordPress isn’t easy, but not broadcasting the version you are using is.

Remove the WordPress version from the <head> tag (no plugin necessary)

Screenshot of meta generator tag showing WordPress version

add_filter( 'the_generator', '__return_empty_string' );

WordPress also uses versions as the default version for enqueued styles and scripts in the ver parameter for cache busting.

Screenshot of WordPress link tags with version in URL

You could use a plugin like Version Assets (shameless self-promotion of OSS) to replace these with content hashes which both obscures the version while optimizing for browser caching.

Use Strong Login Credentials

You can do everything right, but if your login credentials are admin and password you are essentially parking your car with the windows down and the keys on the seat.

Start by requiring a strong password for all users. It’s not as hard as you might think.

Password strength

A simple alternative to coming up with your own password is to use a password manager such as LastPass or 1Password to generate something long and ugly for you. This saves you the trouble of remembering so many passwords. For web developers, your password manager is close to oxygen and coffee in terms of necessity due to the often large number of sites and services we need to maintain credentials for.

One important policy which no plugin can do for you is to not reuse any password that you have used on another site. This is because if the other site becomes compromised (something you likely have little to no control over) and your password known (which it shouldn’t because the password should not be stored in plaintext, but it has happened) or cracked, then the attacker may try using the username/email and password to login to other sites or services.

Whatever you do, don’t use any of the passwords on this list.

Relevant plugins:

  • Force Strong Passwords – Require a minimum level of password strength using the WordPress password strengh meter.
  • Expire Passwords – Require users of selected roles to change their passwords every X days.

Don’t use common administrator usernames

This is another easy one which unnecessarily exposes you to risk simply by using obvious common usernames such as admin or administrator.

If your site uses one of these usernames, create a new admin, and delete the old one (you can always associate all posts/content from the old user with another user when you delete it).

Limit Login Attempts

Chances are you and the users of your site know your respective login credentials fairly well. By default, WordPress does nothing to prevent someone from trying to login hundreds of times per minute or more (besides the fact that your site would probably crash). Does that sound like something you would ever need? Didn’t think so. Let’s not allow that because there are reasonable limits to how many times someone should be able to attempt to log in before we need to let them cool their jets for a few minutes.

The Limit Login Attempts plugin has become a staple among many managed WordPress hosts which you get out-of-the-box when hosting with them. Once a user has X failed login attempts within a given time period, they will be prevented from logging in for the next 10 minutes (or whatever it is set to), even with a correct password. The user then needs to wait for the login ban to expire or contact an administrator on the site who can remove the temporary ban for them.

Use 2-Factor Authentication

2-Factor authentication is an added layer of login security. Your password is the first layer. After the correct password is provided, you must pass a second challenge before you are able to login. This is usually in the form of a 6-9 digit number provided by your phone or another device which you provide in an additional input. The possession of a device you have configured for 2-factor authentication with your site confirms that it is you attempting to log in and not an attacker who happens to have your password.

2-Factor authentication in the real world

My favorite 2FA app is a rather new one called 2FAS which is named after the company behind it. It’s really quick to get started with and has a few really nice features which most others do not: trusted devices, and backup codes in case you lose your device or otherwise need to get in without it. They have their own app for your phone, but you can also use Google Authenticator, or Authy (my favorite as you can use it on your computer too).

Put WordPress in its Own Directory

Not all hosts give you the freedom to do this, but if you can, putting WordPress in its own directory is a very effective way to sidestep a significant amount of malicious traffic knocking on your door.

Diagram comparing WordPress files in a standard install to WordPress files in their own directory

There are other reasons to do this but from a security standpoint, some bots will simply assume your site is using a standard install. Requests for /wp-login.php and /wp-admin/ will fail as 404s because they now reside at /wp/wp-login.php and /wp/wp-admin/. Even if you have a vulnerable plugin installed, if a bot comes by and attempts to exploit it with an assumed standard install path, it will simply miss the target.

Putting WordPress in its own directory also hardens your site to directory traversal attacks, which basically means an attack which exploits a vulnerability in a plugin to say, read the contents of your wp-config.php file by using an expected relative path to it from the plugin file.

E.g.

GET /wp-content/plugins/abcxyz-slider/slide-loader.php?image=../../../../wp-config.php

Keep Regular Backups and Keep Them Far Away

If your server evaporated today, would your site be up and running again tomorrow? Backups are an integral part of running a site which is valuable to you. If your site is hacked somehow, and the damage is irreparable, you should be able to restore to a point before your site was compromised.

In order to be able to restore to a point before your site was hacked without notice, you will need automated backups going back several days. 30 days of backup history is a good number to start with and adjust as necessary for your situation.

Never store your backups on your server

This is important for two reasons:

  1. If your site is ever compromised, the attacker may delete or infect your backups
  2. If your backups became accessible (some plugins create backup files right in the uploads directory) a hacker could download your backup and use that to gain access to the live site

Test performing a restore from backup

The last thing you want to happen when things go wrong is to reach for your trusty backups and for them not to work, or even worse: find out they weren’t being created the whole time. After restoring, make sure any database dumps or other sensitive files that were part of the backup are deleted or not publicly accessible.

Use a Good Host

Having a solid host for your site can really go a long way in keeping your site safe. Particularly a host which specializes in WordPress specifically should offer:

  • A dedicated instance for your site, isolated from all other sites they host
  • Daily offsite backups of your file system and database
  • Daily malware scanning and cleaning of WordPress files

Disable Errors From Outputting to the Screen

If you’ve ever seen PHP errors or notices showing on your screen (usually near the top) then your site is leaking information which could be used against you by an attacker such as what plugins you have installed, or paths on the filesystem. Whether this is enabled or not is largely dependent on how PHP is configured on your server, but it can also be controlled by WordPress’ debugging constants. You may want to add the following to your wp-config.php to prevent errors from being output to the screen. The best way to observe or audit the errors on your site is to enable debug logging, so the errors will be written to a file instead.

define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', true );

You should also block access to the wp-content/debug.log file via HTTP for the same reason.

Plugins and Themes

The vulnerabilities most affecting WordPress website owners stem from the platform’s extensible parts, specifically plugins and themes. These are the #1 attack vector being exploited by cyber criminals to hack and otherwise misuse WordPress sites.
Codex – Hardening WordPress

Auditing your extensions is critical to being on top of keeping your site secure. Try to limit your extensions to those provided by reputable sources, both the author and where you are downloading it from. For free plugins and themes, be sure to get them from wordpress.org if available. For premium extensions, only download them directly from the vendor. Avoid free or “nulled” premium extensions as these can be modified to contain backdoors to allow the “street vendor” to easily gain full access to your site. Remember how your parents always told you to never take candy from strangers? THIS IS THAT CANDY.

Beware of themes which bundle plugins in the theme itself rather than requiring plugin dependencies be installed normally. This is because plugins that are bundled in a theme are not possible to update through the normal auto-update process thus relying on the theme to release updates for its dependencies as well.

Don’t keep plugins or themes installed that you are not using. Even an inactive plugin can be a vulnerability because it is still a part of your codebase and publicly accessible from the web.

Prefer extensions which are updated regularly, and again, update your extensions regularly.

Exercise the Principle of Least Privilege

The principal of least privilege is a term from the information security world which basically says that each part of the system should only have the access and permissions to the resources it needs to do its job and nothing more. Don’t give any more power or access than is required. In WordPress terms, the easiest thing you can do is not make anyone an administrator on your site that doesn’t need to be.

Security Plugins and Services

Reviewing all of the security plugins available for WordPress could be a series in itself, but what article about security in WordPress would be complete without at least mentioning them?

At the time of this writing, the top 3 security plugins on the wordpress.org plugin repository are (in order of most active installs to least):
1. Wordfence Security
2. iThemes Security (formerly Better WP Security)
3. Sucuri Security – Auditing, Malware Scanner and Security Hardening

These plugins offer many features to address the issues and practices outlined above and more. This post is not sponsored by any third-party, but it should help you make a more informed decision as to which plugin might be right for you, should you be considering one.

A few other products worth mentioning are ManageWP and the self-hosted InfiniteWP. These are third-party services which let you remotely administrate your WordPress installs and offer some great security functionality such vulnerability scanning and backups, even at the free tiers. ManageWP gives you more on the free tier but InfiniteWP is something you host yourself and uses add-ons for premium features.

Closing

Securing your website is like trying to keep squirrels out of your birdfeeder; there are always going to be squirrels, you just have to make your feeder harder to reach than the others. Throughout this article, we’ve learned about many different ways that your site can be at risk of being hacked and how to harden it against them.

Of course security is a topic which can hardly be covered comprehensively in a single post, but hopefully, you learned a thing or two that you didn’t know before.

Knowing is half the battle.

What do you do to keep your site secure? Have any tips which you think everyone should know about WordPress security? Sound off in the comments below.

About the Author

Evan Mattson

Evan is a Web Artisan and digital slowmad with deep roots in PHP and WordPress. As an aspiring polyglot and student of software development, he embraces a life of never-ending learning and craftsmanship refinement.

  • I’ve been using a great + free password manager that auto-fills passwords and can autogenerate super long non-sensical passwords that you never have to type or look at is KeePass. I’ve been using the KeeWeb client for Mac. As said above, web devs have thousands of passwords to manage and this software is free and stores them all in an encrypted database. Highly recommended.

  • I integrate Cloudflare on most sites I work on. In addition to the aforementioned best practices. I also use Sucuri’s free plugin in tandem with Wordfence.

  • Lagom Jim

    Thoughts on All-in-One Security? (https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/) I’ve bee using it for a while, but am no expert in the security field.

    • I haven’t used it myself but with over 600k active installs I see that a lot of people are using it! It looks like it has many of the same features as some of the other security plugins. The updates on it seem to be a bit slow, but that’s somewhat expected with a free plugin that does not seem to have a premium version/service to back it.

  • Solid article Evan. Every site owner should understand how to stay protected. Most don’t until they’re hacked.

  • nice article 🙂 it worth to mention changing the database prefix as well…

    • Thanks Roee! There are so many things to mention. I tried to keep it to the most important things that just about everyone can do 🙂

      Regarding changing the database prefix, I know a guy who wrote a plugin to do this if you ever need to do this after the fact 😉

    • If a site owner does only the easiest of what the article points out they will be ahead of the game – even just updating and enforcing strong passwords. Changing db prefix and putting WP in it’s own directory are good, but secondary items on my list.

    • Steve Ryan

      I feel obligated to point out that changing the DB prefix is no longer reported to do anything to help with securing your WordPress install. https://www.wordfence.com/blog/2016/12/wordpress-table-prefix/

    • Wil Brown

      I agree with @steve that there’s absolutely no security advantage in changing the database prefix. If an attacker has access to the DB they can find the prefix using a simple query.

  • We use brute force login protection on most of our sites, it automatically blocks (via htaccess) after a certain number of failed login attempts. This means that the server doesn’t have to load up even a part of WordPress to block in future, Apache handles it, meaning it cuts down on CPU usage quite considerably if you’re being flooded with login attempts. Cerber is a plugin that also lets you block immediately if the username is not recognized, so if you rename the admin user, this is very handy too.

  • Mike Ingala

    While that xkcd comic is mathematically accurate, the four dictionary words in a row approach should not be followed. Hackers read xkcd, too. Brute forcing passwords that are known to contain four dictionary words in a row is easier than long strings of random characters. The longer the stronger.

    • Hey Mike! The image for the comic above links to a really good explanation of it (much better than I could do) but the jist of it is that four random common words is significantly stronger than the kind of a password you might come up with on your own to meet “strong password requirements” which you can memorize. That’s because people are bad at memorizing long truly random strings of gibberish. So is a password that uses 4 common words better than 300 completely random characters? Of course not, but it is better than dbr@1nz4lyf3. (Better go change my password now…)

      • Mike Ingala

        Thanks, Evan. My point was that dbr@1nz4lyf3 is a considerably stronger password than horsestaplebatterywhatever if the hackers are considering four dictionary words as part of their strategy. XKCD is right regarding the relative entropy of the two approaches. They don’t consider that if a bad guy knows the 4 word technique, it becomes considerably easier to brute force than a good long random string. Entropy becomes less relevant.

        The same is true with regard to having public, known requirements for passwords. I know that godaddy requires specific criteria for a valid password. Rather than using a sledgehammer to brute force, I can use a scalpel. All passwords not starting with a letter can immediately be disregarded. All passwords not containing specific special characters can be disregarded. All passwords shorter than 8 characters that don’t contain a number can be disregarded. Etc.

        I use an password manager application that allows for generating long random passwords that don’t require any memorization; just access to the application with a layer of MFA.

  • Jared Chesebro

    Great article.

    I set up my latest WordPress install putting the core files in a subdirectory and then I used a plugin called WPS login to change the location of the login page even further. When I update WordPress will this break the site?

  • Rod Warrix

    WP-Protect. Plug-in works wonders. CHECK it out.

  • evsnm

    The original Limit Login Attempts has not been updated in ages. Maybe try Limit Login Attempts Reloaded which is based on the original plugin.

    • I agree, it’s good to avoid plugins which appear to not be maintained anymore. I mainly mentioned it because some managed hosts (at least in the past) included it as a part of their platform in the form of a must-use plugin. The “Reloaded” version seems to be actively supported so thanks for pointing that out!

  • Biswajit Paul

    Here you can also secure your WordPress site using some htaccess rules: http://tektriks.com/htaccess-for-wordpress-only/

  • Nice Article 😀

  • Craig R Morton

    I think it’s the https://wordpress.org/plugins/wp-limit-login-attempts/ plugin you want to recommend as the Limit Login Attempts plugin you linked hasn’t been maintained in over 2 years.

  • Craig R Morton

    Great post – thanks for putting this together.

  • Kevin VandeKrol

    Suppressing the meta generator tag isn’t enough to prevent version detection… it’s also in the readme.html file (at least the minor version, e.g. “4.7” rather than “4.7.3”), which gets recreated each time you do an update even if you delete it. And if you use wp_enqueue_script() without specifying a version number in the arguments, then it’ll append the full core version number to the end of the script URL. (Some plugins do this too, so you don’t always have direct control over it even if you follow this practice in your own code.)

    I recommend using WPScan (https://wpscan.org/) to get a good idea of what information someone could find about your site if they were looking for exploits. WPScan is not doing anything sophisticated or arcane, just using a collection of basic methods and old-fashioned creativity to find information, and then cross-referencing with a database of exploits based on that information. The scan results will almost certainly surprise you, and serve as a great checklist of things to guard against.

    This is exactly the type of tool a hacker would use, so by seeing what they see and knowing what they know, you’re no longer guarding against an unknown threat.

    • Regarding of the version in the readme.html, this has actually been removed as of version 4.8. There’s a whole lot of conversation about it in these tickets if you have the desire to really dig into it. Access to this file could also be blocked if necessary without too much effort.

      WPScan is a great resource for sure, but it isn’t the kind of thing that everyone has the proficiency to use. Thanks for sharing!

      • Kevin VandeKrol

        I missed the update with version number removal, but that is great news!

        Regarding WPScan… it would be killer if someone could make this into a web service. The Docker setup is definitely beyond the reach of most WP users, but I feel like a crucial part of security is understanding exactly what you are guarding against. If WPScan had a lower barrier to entry, I think it would be a huge asset and would have the potential to increase the community’s practical security awareness in a big way.

  • Hi
    What about Defender by WPMU plugin? You didn’t mention it intentionally?

  • Gene Sorensen

    When you say place WP in a separate directory, is the point having WP in a sub-directory of public_html, or is the point having index.html and the rest of WP in a sub-directory? My host puts all my domains in a sub-directory of public_html and the WP installation in each of those sub-directories, where the index.html is located with the rest of the installation. So am I covered by having

    public-html
    Domain
    index.html
    wp-admin……etc

    Or do I still need to put WP in a sub-directory of Domain1 and have index.html in Domain1?

    How do you get index.html to point to the site if it is not in the same sub-directory?

    • WordPress would go in a subdirectory of the web root for that particular domain. It needs to remain publicly accessible because wp-admin is accessed directly. The web root does not change in the example above; it is public_html in both cases. More info on this here (see Method II).

      • Gene Sorensen

        Thank you, Evan. The link you gave explains it well. But it has this warning:

        “Caveat: Do this at your own risk. For most site owners, it is not recommended to put WordPress in a different directory unless you have a very good reason, and are an experienced and highly skilled WordPress developer, as this can cause issues with a lot of plugins.”

        Could you please address this with the inexperienced user (who is willing to learn and tinker) in mind? I know the “very good reason” is security, but what issues with plugins are they warning about? Is the extra security worth the trouble and extra work? Thanks.

  • Henrique Mattos

    I would love to go through all the comments but there are many. As for the MFA/2-Factor Authentication, I’d like to ensure that it didn’t help at all to stop Brute-Force in WordPress installation and also that Google Authenticator, which is usually used, don’t have iCloud backup and I missed my AWS keys. Now I’m in the limbo for that but that’s another story.

    Anyway, will try the distinct WordPress installation directory to see if it diminishes the brute-force in wp-login.php. Thanks for sharing.

  • Some good points for beginners however, changing your DB prefix and giving WP it’s own directory do little to nothing to improve security. You should have mentioned important .htaccess protections as these are very effective and simple to implement.

  • Gene Sorensen

    Evan, thank you very much. This is very helpful.

    Regards,
    Gene

  • Alfredo Putamadre

    Instead of a login limiter plugin you should add a google captcha plugin, a lot more effective against automated bots.