WAF for WordPress
Stop real-life attacks on your WordPress website and trigger Fail2Ban.
This WAF does not give proper HTTP responses to unusual requests. It blocks the attacking IP address instantly, the purpose of this are the following.
- Prevent website compromise in further requests
- Prevent DoS attacks
Shared hosting has no server-wide banning (because of trust issues) but you can still install this software without Fail2Ban to stop attacks by using one of the Miniban methods.
Support my work
Please consider sponsoring me monthly if you use my packages in an agency.
Theory
Your WordPress - really general HTTP - security consists of the followings.
- Use HTTPS
- Have daily backups
- Block known hostile networks
- Have Fail2Ban installed (controls the firewall)
- Maintain your website and use strict Fail2Ban filters which ban on the first suspicious request instantly
- Deny direct access to core WordPress files, themes and plugins
- Install WAF for WordPress (this project)
- Use Leanmail for filtering Fail2Ban notification emails
See the Block WordPress attack vectors note in my other repository for an overview of the topic.
Composer installation
Technically this is not a WordPress plugin nor an MU plugin. WAF for WordPress is distributed and autoloaded as a Composer package.
- Issue
composer require szepeviktor/waf4wordpress
command - Load
vendor/autoload.php
from yourwp-config
- Instantiate
SzepeViktor\WordPress\Waf\HttpAnalyzer
class early inwp-config
require dirname(__DIR__) . '/vendor/autoload.php'; new SzepeViktor\WordPress\Waf\HttpAnalyzer();
- Create an MU plugin in
wp-content/mu-plugins/waf4wordpress.php
<?php /* * Plugin Name: WAF for WordPress (MU) */ if (! function_exists('add_filter')) { exit; } new SzepeViktor\WordPress\Waf\CoreEvents();
Manual installation
Technically this is not a WordPress plugin nor an MU plugin.
- First download
WAF for WordPress
then extract files to a directory, e.g.
waf/
- Instantiate
SzepeViktor\WordPress\Waf\HttpAnalyzer
class early inwp-config
require_once __DIR__ . '/waf/src/HttpAnalyzer.php'; require_once __DIR__ . '/waf/src/CoreEvents.php'; new SzepeViktor\WordPress\Waf\HttpAnalyzer();
- Create an MU plugin in
wp-content/mu-plugins/waf4wordpress.php
<?php /* * Plugin Name: WAF for WordPress (MU) */ if (! function_exists('add_filter')) { exit; } new SzepeViktor\WordPress\Waf\CoreEvents();
Configuration
WAF for WordPress is configured in source code
before class instantiation. in wp-config
.
Create custom filters for Fail2Ban catching these PHP messages.
- Likely malicious requests:
Malicious traffic detected:
may be banned after 6 attempts per 10 minutes - Surely break-in attempts:
Break-in attempt detected:
may be banned instantly
How to support PayPal IPN, Braintree and custom entry points in poorly written plugins
Copy this into your in wp-config.php
.
// Enable PayPal IPN in WooCommerce
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
if ( '/wc-api/WC_Gateway_Paypal/' === parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) ) {
// PayPal IPN does not send Accept: and User-Agent: headers
$_SERVER['HTTP_ACCEPT'] = '*/*';
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 PayPal/IPN';
}
}
// Enable Braintree Webhooks
new \Waf4WordPress\Braintree_Fix( '/braintree/webhook' );
// Enable email opens in Newsletter plugin
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$newsletter_path = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
if ( '/wp-content/plugins/newsletter/statistics/open.php' === $newsletter_path
|| '/wp-content/plugins/newsletter/statistics/link.php' === $newsletter_path
) {
// UA hack for old email clients
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 ' . $_SERVER['HTTP_USER_AGENT'];
}
unset( $newsletter_path );
}
// Enable email open tracking in ALO EasyMail Newsletter plugin
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$alo_path = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
if ( '/wp-content/plugins/alo-easymail/tr.php' === $alo_path ) {
// UA hack for old email clients
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 ' . $_SERVER['HTTP_USER_AGENT'];
}
unset( $alo_path );
}
Bug reports and feature requests
Where script kiddies look for WordPress
/backup/
/blog/
/cms/
/demo/
/dev/
/home/
/main/
/new/
/old/
/portal/
/site/
/test/
/tmp/
/web/
/wordpress/
/wp/
Best not to create these directories to avoid lengthy log excerpts.