chesio / bc-security

Helps keeping WordPress websites secure.
The Unlicense
14 stars 3 forks source link
wordpress wordpress-plugin wordpress-security

BC Security

GitHub Actions Packagist Coverage Status

A WordPress plugin that helps keeping WordPress websites secure.

Requirements

Limitations

Installation

BC Security is not available at WordPress Plugins Directory, but there are several other ways you can get it.

Using WP-CLI

If you have WP-CLI installed, you can install (and optionally activate) BC Security with a single command:

wp plugin install [--activate] https://github.com/chesio/bc-security/archive/master.zip

Using Composer

Composer is a great tool for managing PHP project dependencies. Although WordPress itself does not make it easy to use Composer to manage WordPress installation as a whole, there are multiple ways how to do it.

BC Security is available at Packagist, so just run composer require chesio/bc-security as usual.

Using Git

Master branch always contains latest stable version, so you can install BC Security by cloning it from within your plugins directory:

cd [your-project]/wp-content/plugins
git clone --single-branch --branch master https://github.com/chesio/bc-security.git

Updating is as easy as:

cd [your-project]/wp-content/plugins/bc-security
git pull

Using Git Updater plugin

BC Security can be installed and updated via Git Updater plugin.

Direct download

This method is the least recommended, but it works without any other tool. You can download BC Security directly from GitHub. Make sure to unpack the plugin into correct directory and drop the version number from folder name.

Setup

Several features of BC Security depends on the knowledge of remote IP address, so it is important that you let the plugin know how your server is connected to the Internet. You can either set connection type via Setup page or with BC_SECURITY_CONNECTION_TYPE constant.

You may also optionally provide Google API key if you want to check your website against the Google Safe Browsing lists of unsafe web resources. The key must have Google Safe Browsing API enabled. As with the connection type, you can configure the key either via Setup page or with BC_SECURITY_GOOGLE_API_KEY constant.

Note: If you already have an installation with BC Security set up and would like to set up another installation in the same way, you can export plugin settings (including connection type) from the former installation and import them to the latter.

Features

Checklist

BC Security can help you find potential security issues or even signs of breach.

Since security measures for development installations do not have to be as strict as for live installations, some checks are run only in live environment. A live environment is determined as one where wp_get_environment_type() returns either production or staging, but there is a dedicated filter that can be used to override live environment detection.

Basic checks

Basic checks cover common security practices. They do not require any information from third party sources to proceed and thus do not leak any information about your website:

  1. Is backend editing of plugin and theme PHP files disabled?
  2. Are directory listings disabled?
  3. Is execution of PHP files from uploads directory forbidden?
  4. Is display of PHP errors off by default? This check is only run in live environment.
  5. Is error log file not publicly available? This check is only run if both WP_DEBUG and WP_DEBUG_LOG constants are set to true.
  6. Are there no common usernames like admin or administrator on the system?
  7. Are user passwords hashed with more secure hashing algorithm than MD5 used by WordPress by default?
  8. Is PHP version still supported?

Advanced checks

Advanced checks require data from external sources, therefore they leak some information about your website and take more time to execute.

In the moment, list of installed plugins (but only those with readme.md or readme.txt file) is shared with WordPress.org and site URL is shared with Google.

WordPress core integrity check

WordPress core files verification is done in two phases:

  1. Official md5 checksums from WordPress.org are used to determine if any of core files have been modified.
  2. All files in root directory, wp-admin directory (including subdirectories) and wp-includes directory (including subdirectories) are checked against official checksums list in order to find out any unknown files.

The check uses the same checksums API as core verify-checksums command from WP-CLI.

Plugins integrity check

Plugin files verification works only for plugins installed from Plugins Directory. The verification process is akin to the core files verification, although the API is slightly different (see related Trac ticket and specification).

Important: any plugins under version control (Git or Subversion) are automatically omitted from the check.

Removed plugins check

Although plugins can be removed from Plugins Directory for several reasons (not only because they have security vulnerability), use of removed plugins is discouraged. Obviously, this check also works only for plugins installed from Plugins Directory.

Safe Browsing check

Checks whether your website is included on any of Google's lists of unsafe web resources - this is usually a solid indicator of compromise. Note that for this check to run you have to provide properly configured API key via plugin setup. This check is only run in live environment.

Checklist monitoring

Both basic and advanced checks can be run manually from a dedicated page in backend, but can be also configured to run periodically (once a day) in the background. Basic checks are run via a single cron job, while each of advanced checks is run via a separate cron job.

WordPress hardening

BC Security allows you to:

  1. Disable pingbacks
  2. Disable XML RPC methods that require authentication
  3. Disable application passwords
  4. Prevent usernames discovery via REST API requests and username enumeration
  5. Disable login with email or login with username to reduce risk from brute-force or credential stuffing attacks.
  6. Check and/or validate user passwords using Pwned Passwords database and API

Passwords check

Passwords are checked on user login. If password is present in the Pwned Passwords database, a non-dismissible warning is displayed in backend encouraging the user to change its password. By default, the warning is displayed on all pages, but this can be customized via a filter.

Passwords validation

Passwords are validated on user creation, password change or password reset. If password is present in the Pwned Passwords database, the operation is aborted with an error message asking user to pick a different password.

Login security

  1. BC Security allows you to limit number of login attempts from single IP address. Implementation of this feature is heavily inspired by popular Limit Login Attempts plugin with an extra feature of immediate blocking of specific usernames (like admin or administrator).
  2. BC Security offers an option to only display generic error message as a result of failed login attempt when wrong username, email or password is provided.

Bad requests banner

Remote IP addresses that are scanning your website for weaknesses can be automatically blocked for configured amount of time. Such scanners can be usually quite easily detected because while scanning a website they trigger a lot of 404 errors and URLs they try to access differ from "valid" 404 errors: usually they try to find a known vulnerable plugin, forgotten backup file or PHP script used for administrative purposes.

There are five built-in rules available (they are not active by default):

  1. ban when non-existent APS file is requested (any URL ending with .asp or .aspx)
  2. ban when non-existent PHP file is requested (any URL ending with .php)
  3. ban when non-existent archive file is requested (any URL ending with .tgz or .zip)
  4. ban when non-existent backup file is requested (any URL targeting file with backup in basename or with .back, .old or .tmp extension)
  5. ban when non-existent readme.txt file is accessed

You may define custom rules as well (in form of regular expression).

Important: When using this feature it is strongly recommended to activate synchronization of internal blocklist with .htaccess file!

Internal blocklist

BC Security maintains a list of IP addresses with limited access to the website. This list is automatically populated by Login security and Bad requests banner modules, but manual addition of IP addresses is also possible.

Out-dated records are automatically removed from the list by WP-Cron job scheduled to run every night. The job can be deactivated in backend, if desired.

Synchronization with .htaccess file

On Apache webserver in version 2.3 or newer, block rules with "website" access scope can be automatically synchronized with .htaccess file. This makes access blocking much more powerful as all requests to the webserver are blocked this way and not only the ones handled by WordPress.

This feature must be however set up manually - following two lines have to be added at the top of root .htaccess file in order for it to work:

# BEGIN BC Security
# END BC Security

After you have completed the setup, either wait for automatic synchronization to kick in on next locking event or run manual synchronization from the administration page.

External blocklist

In addition to internal blocklist, BC Security can be configured to fetch list of IP addresses to block from external sources. Currently only Amazon AWS IP ranges can be used this way.

As with internal blocklist, external blocklist can be used to limit access to entire website or login process only.

Notifications

BC Security allows to send automatic email notification to configured recipients on following occasions:

  1. WordPress update is available.
  2. Plugin update is available.
  3. Theme update is available.
  4. User with administrator privileges has logged in.
  5. Known IP address has been locked out (see note below).
  6. Checklist monitoring triggers an alert. Note: there is one notification sent if any of basic checks fails, but separate notification is sent if any of advanced checks fails.
  7. BC Security plugin has been deactivated.

Note: Known IP address is an IP address from which a successful login attempt had been previously made. Information about successful login attempts is fetched from event logs.

You can mute all email notifications by setting constant BC_SECURITY_MUTE_NOTIFICATIONS to true via define('BC_SECURITY_MUTE_NOTIFICATIONS', true);. If you run a website in multiple environments (development, staging, production etc.), you may find it disturbing to receive email notifications from development or any environment other than production. Declaring the constant for particular environment only is very easy, if you use a multi-environment setup.

Events logging

Following events triggered by BC Security are logged:

  1. Short and long lockout events (see Login Security feature)
  2. Requests blocked by external or internal blocklist (* see note below)
  3. Requests that match any of configured bad request rules

(*) Note: in case internal blocklist is synchronized with .htaccess file, HTTP requests are blocked by webserver before being handled to WordPress, therefore they cannot be logged by the plugin.

Following events triggered by WordPress core are logged:

  1. Attempts to authenticate with bad cookie
  2. Failed and successful login attempts
  3. Requests that result in 404 page

Logs are stored in database and can be viewed on backend. Logs are automatically deleted based on their age and overall size: by default no more than 20 thousands of records are kept and any log records older than 365 days are removed, but these limits can be configured.

Customization

Some of the modules listed above come with settings panel. Further customization can be done with filters provided by plugin:

Credits

  1. Login Security feature is inspired by Limit Login Attempts plugin by Johan Eenfeldt.
  2. WordPress core integrity check is heavily inspired by Checksum Verifier plugin by Sergej Müller.
  3. Some features (like "Removed plugins check" or "Usernames discovery prevention") are inspired by Wordfence Security from Defiant.
  4. Passwords check and passwords validation features uses API and data made available by Have I Been Pwned project by Troy Hunt.
  5. Big thanks to Vincent Driessen for his "A successful Git branching model" article that I find particularly useful every time I do some work on BC Security.
  6. Big thanks to Viktor Szépe for introducing me to PHPStan.
  7. Part of psr/log package codebase is shipped with the plugin.

Alternatives (and why I do not use them)

  1. Wordfence Security - likely the current number one plugin for WordPress Security. My problem with Wordfence is that "when you use [Wordfence], statistics about your website visitors are automatically collected" (see the full Terms of Use and Privacy Policy). In other words, in order to offer some of its great features, Wordfence is phoning home.
  2. All In One WP Security & Firewall - another very popular security plugin for WordPress. I have used AIOWPSF for quite some time; it has a lot of features, but also lot of small bugs (sometimes not that small). I used to contribute to the plugin, but the codebase is rather messy and after some time I got tired struggling with it.