Phase 6: AIOS security plugin with conservative login lockdown config (10 attempts)
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Trait which exits the current request
|
||||
*/
|
||||
trait Action_Exit_Trait {
|
||||
|
||||
/**
|
||||
* Exit when the rule condition is satisfied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function do_action() {
|
||||
Event::raise('action_before_exit');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Combines the forbid and exit trait
|
||||
*/
|
||||
trait Action_Forbid_and_Exit_Trait {
|
||||
|
||||
use Action_Forbid_Trait, Action_Exit_Trait {
|
||||
Action_Forbid_Trait::do_action as protected do_action_forbid;
|
||||
Action_Exit_Trait::do_action as protected do_action_exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forbid 403 and Exit when the rule condition is satisfied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function do_action() {
|
||||
$this->do_action_forbid();
|
||||
$this->do_action_exit();
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Trait to set the header to forbidden
|
||||
*/
|
||||
trait Action_Forbid_Trait {
|
||||
|
||||
/**
|
||||
* Forbid 403 when the rule condition is satisfied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function do_action() {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
trait Action_Permblock_and_Exit_Trait {
|
||||
|
||||
/**
|
||||
* Use the forbid and exit trait
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait {
|
||||
Action_Forbid_and_Exit_Trait::do_action as protected do_action_forbid_and_exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the reason for the perm. block
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $permblock_reason = '';
|
||||
|
||||
/**
|
||||
* Holds the IP for the perm. block
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $permblock_ip = '';
|
||||
|
||||
/**
|
||||
* Sets the reason for the perm. block
|
||||
*
|
||||
* @param string $reason
|
||||
* @return void
|
||||
*/
|
||||
public function set_perm_block_reason($reason) {
|
||||
$this->permblock_reason = $reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the IP for the perm. block
|
||||
*
|
||||
* @param string $ip
|
||||
* @return void
|
||||
*/
|
||||
public function set_perm_block_ip($ip) {
|
||||
$this->permblock_ip = $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently ban the IP and exit when the rule condition is satisfied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function do_action() {
|
||||
|
||||
if (!Utility::attempt_to_access_wpdb()) {
|
||||
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Part of AIOS error reporting system.
|
||||
error_log('AIOS: Unable to access wpdb to ban IP address.');
|
||||
$this->do_action_forbid_and_exit();
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->prefix.'aiowps_permanent_block';
|
||||
|
||||
$ip = empty($this->permblock_ip) ? \AIOS_Helper::get_user_ip_address() : $this->permblock_ip;
|
||||
|
||||
$data = array(
|
||||
'blocked_ip' => $ip,
|
||||
'block_reason' => empty($this->permblock_reason) ? 'firewall_generic' : $this->permblock_reason,
|
||||
'blocked_date' => current_time('mysql')
|
||||
);
|
||||
|
||||
// Check if the IP already exists
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Table name cannot be done via prepare.
|
||||
$already_exists = $wpdb->get_var($wpdb->prepare("SELECT blocked_ip FROM `{$table}` WHERE blocked_ip = %s", $ip));
|
||||
|
||||
// If it does exist, no point adding it again so just forbid and exit
|
||||
if (!is_null($already_exists)) $this->do_action_forbid_and_exit();
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Table name cannot be done via prepare.
|
||||
if (false === $wpdb->query($wpdb->prepare("INSERT INTO " .$table." (blocked_ip, block_reason, blocked_date, created) VALUES (%s, %s, %s, UNIX_TIMESTAMP())", $data['blocked_ip'], $data['block_reason'], $data['blocked_date']))) {
|
||||
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Needed for error reporting.
|
||||
error_log('AIOS: Unable to insert IP address into table.');
|
||||
}
|
||||
|
||||
$this->do_action_forbid_and_exit();
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Combines the redirect and exit trait
|
||||
*/
|
||||
trait Action_Redirect_and_Exit_Trait {
|
||||
|
||||
use Action_Redirect_Trait, Action_Exit_Trait {
|
||||
Action_Redirect_Trait::do_action as protected do_action_redirect;
|
||||
Action_Exit_Trait::do_action as protected do_action_exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect and Exit when the rule condition is satisfied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function do_action() {
|
||||
$this->do_action_redirect();
|
||||
$this->do_action_exit();
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Trait to set the header to redirect
|
||||
*/
|
||||
trait Action_Redirect_Trait {
|
||||
|
||||
/**
|
||||
* Redirect to the location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $location = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* Redirect the rule condition is satisfied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function do_action() {
|
||||
header("Location: $this->location");
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain kinds of data from the query string
|
||||
*/
|
||||
class Rule_Block_Query_Strings_6g extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Block query strings';
|
||||
$this->family = '6G';
|
||||
$this->priority = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
if (empty($_SERVER['QUERY_STRING'])) return Rule::NOT_SATISFIED;
|
||||
|
||||
//Patterns to match against
|
||||
$patterns = array(
|
||||
'/[a-z0-9]{2000,}/i',
|
||||
'/(eval\()/i',
|
||||
'/(127\.0\.0\.1)/i',
|
||||
'/(javascript:)(.*)(;)/i',
|
||||
'/(base64_encode)(.*)(\()/i',
|
||||
'/(GLOBALS|REQUEST)(=|\[|%)/i',
|
||||
'/(<|%3C)(.*)script(.*)(>|%3)/i',
|
||||
'#(\|\.\.\.|\.\./|~|`|<|>|\|)#i',
|
||||
'#(boot\.ini|etc/passwd|self/environ)#i',
|
||||
'/(thumbs?(_editor|open)?|tim(thumb)?)\.php/i',
|
||||
'/(\'|\")(.*)(drop|insert|md5|select|union)/i',
|
||||
);
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
return Rule_Utils::contains_pattern(rawurldecode($_SERVER['QUERY_STRING']), $patterns);
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain referrers recommended by 6G
|
||||
*/
|
||||
class Rule_Block_Refs_6g extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Block referrer strings';
|
||||
$this->family = '6G';
|
||||
$this->priority = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
if (empty($_SERVER['HTTP_REFERER'])) return Rule::NOT_SATISFIED;
|
||||
|
||||
//Patterns to match against
|
||||
$patterns = array(
|
||||
'/[a-z0-9]{2000,}/i',
|
||||
'/(semalt.com|todaperfeita)/i',
|
||||
);
|
||||
|
||||
return Rule_Utils::contains_pattern($_SERVER['HTTP_REFERER'], $patterns); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is not a WordPress context. Also this only evaluates to a boolean.
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain kinds of data from the request string
|
||||
*/
|
||||
class Rule_Block_Request_Strings_6g extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Block request strings';
|
||||
$this->family = '6G';
|
||||
$this->priority = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
if (empty($_SERVER['REQUEST_URI'])) return Rule::NOT_SATISFIED;
|
||||
|
||||
// ensure we get the request uri without the query string
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
$uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
if ('' == $uri) return Rule::NOT_SATISFIED;
|
||||
|
||||
//Patterns to match against
|
||||
$patterns = array(
|
||||
'/[a-z0-9]{2000,}/i',
|
||||
'#(https?|ftp|php):/#i',
|
||||
'#(base64_encode)(.*)(\()#i',
|
||||
'#(=\'|=\%27|/\'/?)\.#i',
|
||||
'#/(\$(\&)?|\*|\"|\.|,|&|&?)/?$#i',
|
||||
'#(\{0\}|\(/\(|\.\.\.|\+\+\+|\\"\\")#i',
|
||||
'#(~|`|<|>|:|;|,|%|\|\s|\{|\}|\[|\]|\|)#i',
|
||||
'#/(=|\$&|_mm|cgi-|etc/passwd|muieblack)#i',
|
||||
'#(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)#i',
|
||||
'#\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$#i',
|
||||
'#/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php#i',
|
||||
);
|
||||
|
||||
return Rule_Utils::contains_pattern(rawurldecode($uri), $patterns);
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain user-agents recommended by 6G
|
||||
*/
|
||||
class Rule_Block_User_Agents_6g extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Block user-agents';
|
||||
$this->family = '6G';
|
||||
$this->priority = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
if (empty($_SERVER['HTTP_USER_AGENT'])) return Rule::NOT_SATISFIED;
|
||||
|
||||
//Patterns to match against
|
||||
$patterns = array(
|
||||
'/[a-z0-9]{2000,}/i',
|
||||
'/(archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune)/i',
|
||||
);
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
return Rule_Utils::contains_pattern($_SERVER['HTTP_USER_AGENT'], $patterns);
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain kinds of HTTP request methods (e.g DEBUG or PUT)
|
||||
*/
|
||||
class Rule_Request_Method_6g extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* List of request methods to block
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $blocked_methods;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
global $aiowps_firewall_config;
|
||||
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Block request methods';
|
||||
$this->family = '6G';
|
||||
$this->priority = 0;
|
||||
|
||||
$this->blocked_methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
return !empty($this->blocked_methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
return isset($_SERVER['REQUEST_METHOD']) && in_array(strtoupper($_SERVER['REQUEST_METHOD']), $this->blocked_methods);
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks IPs to access.
|
||||
*/
|
||||
class Rule_Ips_Blacklist extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* List of IPs / IP range to block
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $blocked_ips;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*
|
||||
* @global Config $aiowps_firewall_config
|
||||
*/
|
||||
public function __construct() {
|
||||
global $aiowps_firewall_config;
|
||||
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Blocked IPs';
|
||||
$this->family = 'Blacklist';
|
||||
$this->priority = 0;
|
||||
$this->blocked_ips = $aiowps_firewall_config->get_value('aiowps_blacklist_ips');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @global Constants $aiowps_firewall_constants
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_constants;
|
||||
if ($aiowps_firewall_constants->AIOS_DISABLE_BLACKLIST_IP_MANAGER) {
|
||||
return false;
|
||||
} else {
|
||||
return !empty($this->blocked_ips);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
$user_ip_blocked = \AIOS_Helper::is_user_ip_address_within_list($this->blocked_ips);
|
||||
|
||||
if (true == $user_ip_blocked) return Rule::SATISFIED;
|
||||
|
||||
return Rule::NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks user agents to access.
|
||||
*/
|
||||
class Rule_User_Agent_Blacklist extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* List of user agents to block
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $blocked_user_agents;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
global $aiowps_firewall_config;
|
||||
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Blocked user agents';
|
||||
$this->family = 'Blacklist';
|
||||
$this->priority = 0;
|
||||
$this->blocked_user_agents = $aiowps_firewall_config->get_value('aiowps_blacklist_user_agents');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
return !empty($this->blocked_user_agents) && isset($_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
foreach ($this->blocked_user_agents as $block_user_agent) {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
if (isset($_SERVER['HTTP_USER_AGENT']) && !empty($block_user_agent) && false !== stripos($_SERVER['HTTP_USER_AGENT'], $block_user_agent)) {
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
}
|
||||
return Rule::NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that bans the IP address if the POST request has a blank user-agent and referer
|
||||
*/
|
||||
class Rule_Ban_Post_Blank_Headers extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Permblock_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Ban POST requests with blank user-agent and referer';
|
||||
$this->family = 'Bots';
|
||||
$this->priority = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_ban_post_blank_headers');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
$this->set_perm_block_reason('firewall_post_blank_user_agent_and_referer');
|
||||
return isset($_SERVER['REQUEST_METHOD']) && (0 === strcasecmp($_SERVER['REQUEST_METHOD'], "POST")) && empty($_SERVER['HTTP_USER_AGENT']) && empty($_SERVER['HTTP_REFERER']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is not a WordPress context. Also this only evaluates to a boolean.
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks fake Googlebots.
|
||||
*/
|
||||
class Rule_Block_Fake_Googlebots extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken.
|
||||
*/
|
||||
use Action_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata.
|
||||
$this->name = 'Block fake Googlebots';
|
||||
$this->family = 'Bots';
|
||||
$this->priority = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active.
|
||||
*
|
||||
* @global Config $aiowps_firewall_config
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_block_fake_googlebots');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply.
|
||||
*
|
||||
* @global Config $aiowps_firewall_config
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
global $aiowps_firewall_config;
|
||||
|
||||
$user_agent = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
|
||||
|
||||
if (preg_match('/Googlebot/i', $user_agent, $matches)) {
|
||||
// If the user agent says it's a Googlebot, start doing checks.
|
||||
|
||||
$ip = \AIOS_Helper::get_user_ip_address();
|
||||
|
||||
if (empty($ip)) {
|
||||
return Rule::NOT_SATISFIED;
|
||||
}
|
||||
|
||||
try {
|
||||
$name = gethostbyaddr($ip); // Let's get the hostname using the IP address.
|
||||
|
||||
if ($name == $ip || false === $name) {
|
||||
// gethostbyaddr failed.
|
||||
$googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
|
||||
if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
|
||||
return Rule::NOT_SATISFIED;
|
||||
} else {
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
$host_ip = gethostbyname($name); // Reverse lookup - let's get the IP address using the hostname.
|
||||
} catch (\Exception $e) {
|
||||
// gethostbyaddr or gethostbyname not available on site.
|
||||
$googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
|
||||
if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
|
||||
return Rule::NOT_SATISFIED;
|
||||
} else {
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
} catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
|
||||
// gethostbyaddr or gethostbyname not available on site.
|
||||
$googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
|
||||
if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
|
||||
return Rule::NOT_SATISFIED;
|
||||
} else {
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/^(?:.+\.)?googlebot\.com$/i', $name) || preg_match('/^(?:.+\.)?google\.com$/i', $name) || preg_match('/^(?:.+\.)?googleusercontent\.com$/i', $name)) {
|
||||
if ($host_ip == $ip) {
|
||||
return Rule::NOT_SATISFIED;
|
||||
} else {
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
} else {
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that uses a cookie to prevent bruteforce attacks.
|
||||
*/
|
||||
class Rule_Cookie_Prevent_Bruteforce extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Redirect_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Cookie based prevent bruteforce';
|
||||
$this->family = 'Bruteforce';
|
||||
$this->priority = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config, $aiowps_firewall_constants;
|
||||
if ($aiowps_firewall_constants->AIOS_DISABLE_COOKIE_BRUTE_FORCE_PREVENTION) {
|
||||
return false;
|
||||
} else {
|
||||
return (bool) $aiowps_firewall_config->get_value('aios_enable_brute_force_attack_prevention');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
global $aiowps_firewall_config;
|
||||
/**
|
||||
* This rule is not applied at AIOS plugin activation time.
|
||||
*/
|
||||
$is_plugins_page = isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('#/wp-admin/(network/)?plugins\.php$#i', $_SERVER['SCRIPT_FILENAME']);
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||
$is_activation_action = isset($_GET['action']) && 'activate' === $_GET['action'];
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||
$is_target_plugin = isset($_GET['plugin']) && 'all-in-one-wp-security-and-firewall/wp-security.php' === $_GET['plugin'];
|
||||
|
||||
|
||||
if ($is_plugins_page && $is_activation_action && $is_target_plugin) {
|
||||
return Rule::NOT_SATISFIED;
|
||||
}
|
||||
|
||||
$brute_force_secret_word = $aiowps_firewall_config->get_value('aios_brute_force_secret_word');
|
||||
$brute_force_secret_cookie_name = $aiowps_firewall_config->get_value('aios_brute_force_secret_cookie_name');
|
||||
$login_page_slug = $aiowps_firewall_config->get_value('aios_login_page_slug');
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||
if (!isset($_GET[$brute_force_secret_word])) {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
|
||||
$brute_force_secret_cookie_val = isset($_COOKIE[$brute_force_secret_cookie_name]) ? $_COOKIE[$brute_force_secret_cookie_name] : '';
|
||||
$pw_protected_exception = $aiowps_firewall_config->get_value('aios_brute_force_attack_prevention_pw_protected_exception');
|
||||
$prevent_ajax_exception = $aiowps_firewall_config->get_value('aios_brute_force_attack_prevention_ajax_exception');
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
|
||||
if (!empty($_SERVER['REQUEST_URI']) && !hash_equals($brute_force_secret_cookie_val, \AIOS_Helper::get_hash($brute_force_secret_word))) {
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
|
||||
$request_uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
// admin section or login page or login custom slug called
|
||||
$is_admin_or_login = (false != strpos($request_uri, 'wp-admin') || false != strpos($request_uri, 'wp-login') || ('' != $login_page_slug && false != strpos($request_uri, $login_page_slug))) ? 1 : 0;
|
||||
|
||||
// admin side ajax called
|
||||
$is_admin_ajax_request = ('1' == $prevent_ajax_exception && isset($_SERVER['SCRIPT_NAME']) && ('admin-ajax.php' === basename($_SERVER['SCRIPT_NAME']))) ? 1 : 0;
|
||||
|
||||
// password protected page called
|
||||
$is_password_protected_access = ('1' == $pw_protected_exception && isset($_GET['action']) && 'postpass' == $_GET['action']) ? 1 : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||
|
||||
// logout, set password, reset password action called
|
||||
$is_logout_resetpassword_action = (isset($_GET['action']) && ('logout' == $_GET['action'] || 'rp' == $_GET['action'] || 'resetpass' == $_GET['action'])) ? 1 : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||
|
||||
// cookie based brute force on and accessing admin without ajax and password protected then redirect
|
||||
if ($is_admin_or_login && !$is_admin_ajax_request && !$is_password_protected_access && !$is_logout_resetpassword_action) {
|
||||
$redirect_url = $aiowps_firewall_config->get_value('aios_cookie_based_brute_force_redirect_url');
|
||||
$this->location = $redirect_url;
|
||||
return Rule::SATISFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Rule::NOT_SATISFIED;
|
||||
}
|
||||
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain kinds of data from the request string
|
||||
*/
|
||||
class Rule_Advanced_Character_Filter extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Advanced character filter';
|
||||
$this->family = 'General';
|
||||
$this->priority = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_advanced_char_string_filter');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
if (empty($_SERVER['REQUEST_URI'])) return Rule::NOT_SATISFIED;
|
||||
|
||||
// ensure we get the request uri without the query string
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
$uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
return Rule_Utils::contains_pattern($uri, array_merge($this->get_general_characters(), $this->get_common_patterns(), $this->get_specific_exploits()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of 'specific exploits' patterns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_specific_exploits() {
|
||||
return array(
|
||||
'/errors\./i',
|
||||
'/config\./i',
|
||||
'/include\./i',
|
||||
'/display\./i',
|
||||
'/register\./i',
|
||||
'/password\./i',
|
||||
'/maincore\./i',
|
||||
'/authorize\./i',
|
||||
'/macromates\./i',
|
||||
'/head\_auth\./i',
|
||||
'/submit\_links\./i',
|
||||
'/change\_action\./i',
|
||||
'/com\_facileforms\//i',
|
||||
'/admin\_db\_utilities\./i',
|
||||
'/admin\.webring\.docs\./i',
|
||||
'/Table\/Latest\/index\./i',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of common patterns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_common_patterns() {
|
||||
return array(
|
||||
'/\_vpi/i',
|
||||
'/\.inc/i',
|
||||
'/xAou6/i',
|
||||
'/db\_name/i',
|
||||
'/select\(/i',
|
||||
'/convert\(/i',
|
||||
'/\/query\//i',
|
||||
'/ImpEvData/i',
|
||||
'/\.XMLHTTP/i',
|
||||
'/proxydeny/i',
|
||||
'/function\./i',
|
||||
'/remoteFile/i',
|
||||
'/servername/i',
|
||||
'/\&rptmode\=/i',
|
||||
'/sys\_cpanel/i',
|
||||
'/db\_connect/i',
|
||||
'/doeditconfig/i',
|
||||
'/check\_proxy/i',
|
||||
'/system\_user/i',
|
||||
'/\/\(null\)\//i',
|
||||
'/clientrequest/i',
|
||||
'/option\_value/i',
|
||||
'/ref\.outcontrol/i',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of general characters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_general_characters() {
|
||||
return array(
|
||||
'/\,/i',
|
||||
'/\:/i',
|
||||
'/\;/i',
|
||||
'/\=/i',
|
||||
'/\[/i',
|
||||
'/\]/i',
|
||||
'/\^/i',
|
||||
'/\`/i',
|
||||
'/\{/i',
|
||||
'/\}/i',
|
||||
'/\~/i',
|
||||
'/\"/i',
|
||||
'/\$/i',
|
||||
'/\</i',
|
||||
'/\>/i',
|
||||
'/\|/i',
|
||||
'/\.\./i',
|
||||
'/\%0/i',
|
||||
'/\%A/i',
|
||||
'/\%B/i',
|
||||
'/\%C/i',
|
||||
'/\%D/i',
|
||||
'/\%E/i',
|
||||
'/\%F/i',
|
||||
'/\%22/i',
|
||||
'/\%27/i',
|
||||
'/\%28/i',
|
||||
'/\%29/i',
|
||||
'/\%3C/i',
|
||||
'/\%3E/i',
|
||||
'/\%3F/i',
|
||||
'/\%5B/i',
|
||||
'/\%5C/i',
|
||||
'/\%5D/i',
|
||||
'/\%7B/i',
|
||||
'/\%7C/i',
|
||||
'/\%7D/i',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks certain data from the URL's query string
|
||||
*/
|
||||
class Rule_Bad_Query_Strings extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Bad query strings';
|
||||
$this->family = 'General';
|
||||
$this->priority = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_deny_bad_query_strings');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
if (empty($_SERVER['QUERY_STRING'])) return Rule::NOT_SATISFIED;
|
||||
|
||||
$patterns = array(
|
||||
'/ftp:/i',
|
||||
'/http:/i',
|
||||
'/https:/i',
|
||||
'/mosConfig/i',
|
||||
'/^.*(globals|encode|loopback).*/i',
|
||||
"/(\;|'|\"|%22).*(request|insert|union|declare|drop)/i",
|
||||
);
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
return Rule_Utils::contains_pattern($_SERVER['QUERY_STRING'], $patterns);
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks access to the xmlrpc.php file
|
||||
*/
|
||||
class Rule_Block_Xmlrpc extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Completely block XMLRPC';
|
||||
$this->family = 'General';
|
||||
$this->priority = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_enable_pingback_firewall');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
return (isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('/\/xmlrpc\.php$/i', $_SERVER['SCRIPT_FILENAME']));
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Rule that blocks comments being posted if a proxy is detected.
|
||||
*/
|
||||
class Rule_Proxy_Comment_Posting extends Rule {
|
||||
|
||||
/**
|
||||
* Implements the action to be taken
|
||||
*/
|
||||
use Action_Forbid_and_Exit_Trait;
|
||||
|
||||
/**
|
||||
* Construct our rule
|
||||
*/
|
||||
public function __construct() {
|
||||
// Set the rule's metadata
|
||||
$this->name = 'Proxy comment posting';
|
||||
$this->family = 'General';
|
||||
$this->priority = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active() {
|
||||
global $aiowps_firewall_config;
|
||||
return (bool) $aiowps_firewall_config->get_value('aiowps_forbid_proxy_comments');
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition to be satisfied for the rule to apply
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_satisfied() {
|
||||
|
||||
//Preconditions for the rule
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
$is_comment_form = (isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('/\/wp-comments-post\.php$/i', $_SERVER['SCRIPT_FILENAME']));
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||
$is_post = (isset($_SERVER['REQUEST_METHOD']) && 0 === strcasecmp($_SERVER['REQUEST_METHOD'], "POST"));
|
||||
|
||||
if (!$is_post || !$is_comment_form) return Rule::NOT_SATISFIED;
|
||||
|
||||
//Headers that are present if a proxy is being used
|
||||
$headers = array(
|
||||
'HTTP_VIA',
|
||||
'HTTP_FORWARDED',
|
||||
'HTTP_USERAGENT_VIA',
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
'HTTP_X_FORWARDED_HOST',
|
||||
'HTTP_PROXY_CONNECTION',
|
||||
'HTTP_XPROXY_CONNECTION',
|
||||
'HTTP_PC_REMOTE_ADDR',
|
||||
'HTTP_CLIENT_IP',
|
||||
);
|
||||
|
||||
foreach ($headers as $header) {
|
||||
if (!empty($_SERVER[$header])) return Rule::SATISFIED;
|
||||
}
|
||||
|
||||
return Rule::NOT_SATISFIED;
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Builds our rules
|
||||
*/
|
||||
class Rule_Builder {
|
||||
|
||||
/**
|
||||
* Gets our rule if it's active
|
||||
*
|
||||
* @return iterable
|
||||
*/
|
||||
public static function get_active_rule() {
|
||||
|
||||
foreach (self::get_rule_classname() as $classname) {
|
||||
|
||||
$rule = new $classname();
|
||||
|
||||
if (!$rule->is_active()) {
|
||||
Event::raise('rule_not_active', $rule, $classname);
|
||||
continue;
|
||||
}
|
||||
|
||||
Event::raise('rule_active', $rule, $classname);
|
||||
yield $rule;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the classname for each rule
|
||||
*
|
||||
* @return iterable
|
||||
*/
|
||||
private static function get_rule_classname() {
|
||||
$rec_iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(AIOWPS_FIREWALL_DIR.'/rule/rules/', \FilesystemIterator::SKIP_DOTS));
|
||||
|
||||
foreach ($rec_iterator as $dir_iterator) {
|
||||
$matches = array();
|
||||
if (preg_match('/^rule-(?<rule_name>.*)\.php$/', $dir_iterator->getFilename(), $matches)) {
|
||||
yield "AIOWPS\Firewall\Rule_".ucwords(str_replace('-', '_', $matches['rule_name']), '_');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Utility methods to help with the rules
|
||||
*/
|
||||
class Rule_Utils {
|
||||
|
||||
/**
|
||||
* Check if the subject contains the given pattern or patterns
|
||||
*
|
||||
* @param string $subject - The subject we wish to check the pattern or patterns against.
|
||||
* @param string|array $pattern - Regex pattern. An array for multiple patterns; a string otherwise.
|
||||
* @return boolean
|
||||
*/
|
||||
public static function contains_pattern($subject, $pattern) {
|
||||
|
||||
if (empty($subject)) return false;
|
||||
|
||||
if (is_string($pattern)) return (1 === preg_match($pattern, $subject));
|
||||
|
||||
if (!is_array($pattern)) return false;
|
||||
|
||||
foreach ($pattern as $patt) {
|
||||
if (preg_match($patt, $subject)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace AIOWPS\Firewall;
|
||||
|
||||
/**
|
||||
* Base class for our firewall rules
|
||||
*/
|
||||
abstract class Rule {
|
||||
|
||||
/**
|
||||
* Name of the rule
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Name of the family the rule belongs to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $family;
|
||||
|
||||
/**
|
||||
* Rule's priority (0 is the highest)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $priority;
|
||||
|
||||
/**
|
||||
* An abstraction for when the rule is satisfied
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
const SATISFIED = true;
|
||||
|
||||
/**
|
||||
* An abstraction for when the rule is not satisfied
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
const NOT_SATISFIED = false;
|
||||
|
||||
|
||||
/**
|
||||
* Executes the rule's action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function do_action();
|
||||
|
||||
/**
|
||||
* Check if the rule is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function is_active();
|
||||
|
||||
/**
|
||||
* Check if the rule has been satisfied
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function is_satisfied();
|
||||
|
||||
/**
|
||||
* Apply the rule and execute the action if satisfied
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function apply() {
|
||||
|
||||
if ($this->is_satisfied()) {
|
||||
|
||||
Event::raise('rule_triggered', $this, time());
|
||||
$this->do_action();
|
||||
|
||||
}
|
||||
|
||||
Event::raise('rule_not_triggered', $this, time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the rule's name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user