Skip to content

Commit

Permalink
added version 1.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
developeregrem committed Mar 2, 2023
1 parent 07bf1e4 commit 27ce640
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 11 deletions.
166 changes: 166 additions & 0 deletions wp-author-security/WPASData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<?php

namespace WP_Author_Security;

class WPASData
{

public static $dbVersion = "1.0";
const TYPE_GENERAL = 99;
const TYPE_AUTHOR_REQUEST = 1;
const TYPE_REST_API_USER = 2;
const TYPE_LOGIN_PWRESET = 3;
const TYPE_FEED = 4;
const TYPE_OEMBED = 5;
const TYPE_SITEMAP_AUTHOR = 6;
const KEY_LAST_ACTION = 'last_action';
const KEY_ALL_COUNT = 'all';

public function __construct() {
global $wpdb;

// Registering meta table
$wpdb->wpas_statisticmeta = $wpdb->prefix . 'wpas_statisticmeta';
//$this->cleanUp();
}

/**
* Setup of the database
* @return void
*/
public static function createDB() {
global $wpdb;

require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
$table_name = $wpdb->prefix . "wpas_statisticmeta";
$charset_collate = $wpdb->get_charset_collate();

$schema = "CREATE TABLE {$table_name} (
meta_id bigint(20) NOT NULL AUTO_INCREMENT,
wpas_statistic_id bigint(20) NOT NULL DEFAULT '0',
meta_key varchar(255) DEFAULT NULL,
meta_value longtext,
PRIMARY KEY meta_id (meta_id),
KEY myplugin_product_id (wpas_statistic_id),
KEY meta_key (meta_key)
) {$charset_collate };";

dbDelta( $schema );

add_option( "wpas_db_version", WPASData::$dbVersion );
}

public static function uninstall() {
global $wpdb;
$table_name = $wpdb->prefix . "wpas_statisticmeta";
$sql = "DROP TABLE IF EXISTS {$table_name}";
$wpdb->query($sql);

delete_option('wpas_db_version');
delete_option( 'protectAuthor');
delete_option( 'protectAuthorName');
delete_option( 'disableLoggedIn');
delete_option( 'disableRestUser');
delete_option( 'customLoginError');
delete_option( 'wpas_filterFeed');
delete_option( 'wpas_filterEmbed');
delete_option( 'wpas_filterAuthorSitemap');
}

/**
* Checks whether the db schema needs to be updated
* @return void
*/
public static function updateDbCheck() {
if ( get_site_option( 'wpas_db_version' ) !== WPASData::$dbVersion ) {
WPASData::createDB();
}
}

public function getMeta( $id, $meta_key, $single = true ) {
return get_metadata( 'wpas_statistic', $id, $meta_key, $single );
}

public function updateMeta( $id, $meta_key, $value ='' ) {
return update_metadata( 'wpas_statistic', $id, $meta_key, $value );
}

public function addMeta( $id, $meta_key, $value ='' ) {
return add_metadata( 'wpas_statistic', $id, $meta_key, $value, true );
}

public function deleteMeta( $id, $meta_key = '' ) {
return delete_metadata( 'wpas_statistic', $id, $meta_key );
}

public function addOrUpdate($id, $meta_key, $value = '' ) {
$count = $this->getMeta($id, $meta_key);
if(empty($count) && $count !== '0') {
return $this->addMeta($id, $meta_key, "1");
} else {
return $this->updateMeta($id, $meta_key, (empty($value) ? ++$count : $value));
}
}

/**
* Returns the number of days between two days
* @param DateTimeInterface $start
* @param DateTimeInterface $end
* @return string
*/
private function getDateDiffDays(\DateTimeInterface $start, \DateTimeInterface $end) {
$interval = date_diff($start, $end);

// return number of days
return $interval->format('%a');
}

/**
* Returns the total number of malicious requests
* @return string
*/
public function getCountAll() : string {
$count = $this->getMeta(WPASData::TYPE_GENERAL, WPASData::KEY_ALL_COUNT);
return (empty($count) ? '0' : $count);
}

/**
* Calculates the number of malicious requests in the past 7 days
* @return int
*/
public function getCountLastDays() : int {
$count = 0;
for($i=1; $i<=7; $i++) {
$dayCount = $this->getMeta(WPASData::TYPE_GENERAL, 'weekday_' . $i);
if(!empty($dayCount)) {
$count += $dayCount;
}
}
return $count;
}

/**
* Reset counter for days of previous week(s)
* @return void
* @throws Exception
*/
public function cleanUp() {
$lastAction = $this->getMeta(WPASData::TYPE_GENERAL, WPASData::KEY_LAST_ACTION);
if(empty($lastAction)) {
return;
}
$today = new \DateTime();
$lastDate = new \DateTime($lastAction);
$days = $this->getDateDiffDays($lastDate, $today);

// do nothing when last action is within one week
if($days <= 6) {
return;
}
// loop over days that need to be reset
for($i = 1; $i <= 7; $i++) {
// reset for all possible types
$this->updateMeta(WPASData::TYPE_GENERAL, 'weekday_' . $i, 0);
}
}
}
Binary file modified wp-author-security/languages/wp-author-security-de_DE.mo
Binary file not shown.
4 changes: 4 additions & 0 deletions wp-author-security/languages/wp-author-security-de_DE.po
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,7 @@ msgstr "https://github.com/mgm-sp/wp-author-security"
#. Plugin Name of the plugin
msgid "WP Author Security"
msgstr "WP Author Security"

#: options.php:121
msgid "Blocked %d malicious requests since activation and %d requests in the past 7 days."
msgstr "Insgesamt %d verdächtige Anfragen seit der Aktivierung geblockt und %d Anfragen innerhalb der letzten 7 Tage."
16 changes: 12 additions & 4 deletions wp-author-security/options.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use WP_Author_Security\WPASData;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
Expand Down Expand Up @@ -85,7 +86,6 @@ function register_wp_author_security_settings() {
register_setting( 'wp-author-security-group', 'wpas_filterFeed', array_merge($argsBase, $argsFilterFeed) );
register_setting( 'wp-author-security-group', 'wpas_filterEmbed', array_merge($argsBase, $argsFilterEmbed) );
register_setting( 'wp-author-security-group', 'wpas_filterAuthorSitemap', array_merge($argsBase, $argsFilterAuthorSitemap) );

};

function wp_author_security_menu() {
Expand All @@ -112,10 +112,18 @@ function wpas_sanitize_int ( $input ) {
* display Option's page
*/
function wp_author_security_options_page() {
$wpasMeta = new WPASData();
?>

<div class="wrap">
<h2><?php echo __('WP Author Security Settings', 'wp-author-security'); ?></h2>
<div class="wrap">
<h2><?php echo __('WP Author Security Settings', 'wp-author-security'); ?></h2>
<p style="font-style: italic;">
<?php echo sprintf( __( 'Blocked %d malicious requests since activation and %d requests in the past 7 days.', 'wp-author-security' ),
$wpasMeta->getCountAll(),
$wpasMeta->getCountLastDays()
);
?>
</p>
<form method="post" action="options.php">
<?php settings_fields( 'wp-author-security-group' ); ?>
<?php do_settings_sections( 'wp-author-security-group' ); ?>
Expand Down Expand Up @@ -212,7 +220,7 @@ function wp_author_security_options_page() {

<?php submit_button(); ?>

</form>
</form>
</div>
<?php
}
Expand Down
10 changes: 7 additions & 3 deletions wp-author-security/readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
Contributors: mgmsp
Tags: security, user-enumeration, privacy, author, wpscan
Requires at least: 4.7
Tested up to: 6.0
Requires PHP: 5.6
Stable tag: 1.4.1
Tested up to: 6.1
Requires PHP: 7.4
Stable tag: 1.5.0
License: GPLv3

Protect against user enumeration attacks on author pages and other places where valid user names can be obtained.
Expand Down Expand Up @@ -38,6 +38,10 @@ In addition, the plugin will also protect other locations which are commonly use

== Changelog ==

= 1.5.0 =
* added basic statistics to the settings page
* bugfix password forgotten protection

= 1.4.1 =
* Bugfix error on login check

Expand Down
48 changes: 44 additions & 4 deletions wp-author-security/wp-author-security.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@
* Description: Protect against user enumeration attacks on author pages and other places where valid user names can be obtained.
* Author: mgmsp
* Author URI: https://www.mgm-sp.com
* Version: 1.4.1
* Version: 1.5.0
* License: GPLv3
* Plugin URI: https://github.com/mgm-sp/wp-author-security
*/

use WP_Author_Security\WPASData;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

require_once (dirname( __FILE__ ) . '/WPASData.php');
require_once (dirname( __FILE__ ) . '/options.php');

/**
* initialize the plugin
*/
function wpas_init() {

add_action( 'template_redirect', 'wpas_check_author_request', 1 );
add_action( 'rest_api_init', 'wpas_check_rest_api', 10 );
add_action( 'plugins_loaded', 'wpas_load_plugin_textdomain' );
Expand All @@ -31,7 +34,10 @@ function wpas_init() {
add_filter( 'oembed_response_data', 'wpas_filter_oembed', 10, 4 );
// since wp 5.5
add_filter( 'wp_sitemaps_add_provider', 'wpas_filter_wp_sitemap_author', 10, 2 );


register_activation_hook( __FILE__, ['WP_Author_Security\WPASData', 'createDB'] );
register_uninstall_hook( __FILE__, ['WP_Author_Security\WPASData', 'uninstall'] );
add_action( 'plugins_loaded', ['WP_Author_Security\WPASData', 'updateDbCheck'] );
}

/**
Expand Down Expand Up @@ -71,6 +77,7 @@ function wpas_check_author_request() {

// when protection is enabled display 404
if( $disable ) {
wpas_incrementStatistics(WPASData::TYPE_AUTHOR_REQUEST);
wpas_display_404();
}

Expand All @@ -90,6 +97,7 @@ function wpas_check_rest_api()
$requestUriMatch = (isset($_SERVER['REQUEST_URI']) && preg_match($pattern, $_SERVER['REQUEST_URI']));
if( $restRouteMatch || $requestUriMatch ) {
if(get_option( 'disableRestUser' )) {
wpas_incrementStatistics(WPASData::TYPE_REST_API_USER);
wpas_display_404();
}
}
Expand Down Expand Up @@ -160,6 +168,7 @@ function wpas_login_error_message($error){
in_array( 'incorrect_password', $err_codes ) ) {
//its the right error so we can overwrite it
$error = sprintf( __( 'The entered username or password is not correct. <a href=%s>Lost your password</a>?', 'wp-author-security' ), wp_lostpassword_url() );
wpas_incrementStatistics(WPASData::TYPE_LOGIN_PWRESET);
}
}

Expand All @@ -180,8 +189,10 @@ function wpas_check_lost_password_error($errors) {

if( is_wp_error( $errors ) ) {
if( $errors->get_error_code() === 'invalidcombo' || $errors->get_error_code() === 'invalid_email' ) {
wpas_incrementStatistics(WPASData::TYPE_LOGIN_PWRESET);
$redirect = 'wp-login.php?checkemail=confirm';
wp_safe_redirect($redirect);
exit();
}
}
return;
Expand All @@ -198,8 +209,9 @@ function wpas_filter_feed($displayName) {
if( !get_option( 'wpas_filterFeed') || !wpas_is_enabled_for_logged_in() ) {
return $displayName;
}

if ( is_feed() ) {
wpas_incrementStatistics(WPASData::TYPE_FEED);
return '';
}

Expand All @@ -224,6 +236,7 @@ function wpas_filter_oembed( $data, $post, $width, $height ) {

unset($data['author_name']);
unset($data['author_url']);
wpas_incrementStatistics(WPASData::TYPE_OEMBED);

return $data;
};
Expand All @@ -241,6 +254,8 @@ function wpas_filter_wp_sitemap_author( $provider, $name ) {
}

if ( 'users' === $name ) {
// currently disabled as this hook fires almost on every request
// wpas_incrementStatistics(WPASData::TYPE_SITEMAP_AUTHOR);
return false;
}

Expand All @@ -263,4 +278,29 @@ function wpas_load_plugin_textdomain() {
load_plugin_textdomain( 'wp-author-security', false, basename( dirname( __FILE__ ) ) . '/languages/' );
}

function wpas_incrementStatistics($type) {
$wpasMeta = new WPASData();
$wpasMeta->cleanUp();
$wpasMeta->addOrUpdate(WPASData::TYPE_GENERAL, WPASData::KEY_ALL_COUNT);

$lastAction = $wpasMeta->getMeta(WPASData::TYPE_GENERAL, WPASData::KEY_LAST_ACTION);
$time = date("Y-m-d H:i:s");
$currentWeekDay = date("N");
if(empty($lastAction)) {
$wpasMeta->addMeta(WPASData::TYPE_GENERAL, WPASData::KEY_LAST_ACTION, $time);
$lastAction = $time;
} else {
$wpasMeta->updateMeta(WPASData::TYPE_GENERAL, WPASData::KEY_LAST_ACTION, $time);
}

$oldDate = new \DateTime($lastAction);
if($oldDate->format("N") !== $currentWeekDay) {
// reset count because we have a new day
$wpasMeta->addOrUpdate(WPASData::TYPE_GENERAL, 'weekday_' . $currentWeekDay, 1);
} else {
// otherwise increment count for day
$wpasMeta->addOrUpdate(WPASData::TYPE_GENERAL, 'weekday_' . $currentWeekDay);
}
}

wpas_init();

0 comments on commit 27ce640

Please sign in to comment.