408 lines
12 KiB
PHP
408 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* MainWP Security
|
|
*
|
|
* @package MainWP/Child
|
|
*/
|
|
|
|
namespace MainWP\Child;
|
|
|
|
/**
|
|
* Class MainWP_Security
|
|
*
|
|
* Detect security issues
|
|
*/
|
|
class MainWP_Security { //phpcs:ignore -- NOSONAR - multi methods.
|
|
|
|
/**
|
|
* Method get_class_name()
|
|
*
|
|
* Get class name.
|
|
*
|
|
* @return string __CLASS__ Class name.
|
|
*/
|
|
public static function get_class_name() {
|
|
return __CLASS__;
|
|
}
|
|
|
|
/**
|
|
* Method fix_all()
|
|
*
|
|
* Fire off functions to fix detected security issues.
|
|
*
|
|
* @uses MainWP_Security::remove_php_reporting() Disable the PHP error reporting.
|
|
* @uses MainWP_Security::remove_script_versions() Remove scripts and stylesheets versions.
|
|
* @uses MainWP_Security::remove_theme_versions() Remove themes scripts and stylesheets version.
|
|
*/
|
|
public static function fix_all() {
|
|
static::remove_php_reporting();
|
|
|
|
if ( static::get_security_option( 'db_reporting' ) ) {
|
|
static::remove_database_reporting();
|
|
}
|
|
|
|
add_filter( 'style_loader_src', array( static::get_class_name(), 'remove_script_versions' ), PHP_INT_MAX );
|
|
add_filter( 'style_loader_src', array( static::get_class_name(), 'remove_theme_versions' ), PHP_INT_MAX );
|
|
add_filter( 'script_loader_src', array( static::get_class_name(), 'remove_script_versions' ), PHP_INT_MAX );
|
|
add_filter( 'script_loader_src', array( static::get_class_name(), 'remove_theme_versions' ), PHP_INT_MAX );
|
|
}
|
|
|
|
/**
|
|
* Private static variable to hold the directory listing information.
|
|
*
|
|
* @var mixed Default null
|
|
*/
|
|
private static $listingDirectories = null;
|
|
|
|
/**
|
|
* Method init_listing_directories()
|
|
*
|
|
* Get directories array to prevent listing.
|
|
*/
|
|
private static function init_listing_directories() {
|
|
if ( null === static::$listingDirectories ) {
|
|
$wp_upload_dir = wp_upload_dir();
|
|
static::$listingDirectories = array(
|
|
WP_CONTENT_DIR,
|
|
WP_PLUGIN_DIR,
|
|
get_theme_root(),
|
|
$wp_upload_dir['basedir'],
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method prevent_listing()
|
|
*
|
|
* Prevent directory listing by creating the index.php file.
|
|
*
|
|
* @used-by \MainWP\Child\MainWP_Security::fix_all() Fire off functions to fix detected security issues.
|
|
* @uses \MainWP\Child\MainWP_Helper::get_wp_filesystem()
|
|
*/
|
|
public static function prevent_listing() {
|
|
static::init_listing_directories();
|
|
|
|
/**
|
|
* Global variable containing the instance of the (auto-)configured filesystem object after the filesystem "factory" has been run.
|
|
*
|
|
* @global object $wp_filesystem Filesystem object.
|
|
*/
|
|
global $wp_filesystem;
|
|
|
|
MainWP_Helper::get_wp_filesystem();
|
|
|
|
foreach ( static::$listingDirectories as $directory ) {
|
|
$file = $directory . DIRECTORY_SEPARATOR . 'index.php';
|
|
if ( ! $wp_filesystem->exists( $file ) ) {
|
|
$content = "<?php \n";
|
|
$content .= "header(\$_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden' );\n";
|
|
$content .= "die( '403 Forbidden' );\n";
|
|
$wp_filesystem->put_contents( $file, $content );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method remove_php_reporting()
|
|
*
|
|
* Disable the PHP error reporting.
|
|
*
|
|
* @param bool $force Force action if true, don't force if false.
|
|
*
|
|
* @used-by MainWP_Security::fix_all() Fire off functions to fix detected security issues.
|
|
*/
|
|
public static function remove_php_reporting( $force = false ) {
|
|
if ( $force || static::get_security_option( 'php_reporting' ) ) {
|
|
error_reporting( 0 ); //phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
|
|
ini_set( 'display_errors', 'off' ); //phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
|
|
ini_set( 'display_startup_errors', 0 ); //phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method remove_database_reporting()
|
|
*
|
|
* Disable the database error reporting.
|
|
*
|
|
* @used-by MainWP_Security::fix_all() Fire off functions to fix detected security issues.
|
|
*/
|
|
public static function remove_database_reporting() {
|
|
|
|
/**
|
|
* Object, providing access to the WordPress database.
|
|
*
|
|
* @global $wpdb WordPress Database instance.
|
|
*/
|
|
global $wpdb;
|
|
|
|
$wpdb->hide_errors();
|
|
$wpdb->suppress_errors();
|
|
}
|
|
|
|
/**
|
|
* Method remove_script_versions()
|
|
*
|
|
* Remove scripts versions.
|
|
*
|
|
* @param string $src Script or stylesheet location path.
|
|
*
|
|
* @used-by MainWP_Security::fix_all() Fire off functions to fix detected security issues.
|
|
*
|
|
* @return string $src Script or stylesheet striped location path.
|
|
*/
|
|
public static function remove_script_versions( $src ) {
|
|
if ( static::get_security_option( 'scripts_version' ) ) {
|
|
if ( strpos( $src, '?ver=' ) ) {
|
|
$src = remove_query_arg( 'ver', $src );
|
|
}
|
|
return $src;
|
|
}
|
|
return $src;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method remove_theme_versions()
|
|
*
|
|
* Remove themes versions.
|
|
*
|
|
* @param string $src Theme stylesheet location path.
|
|
*
|
|
* @used-by MainWP_Security::fix_all() Fire off functions to fix detected security issues.
|
|
*
|
|
* @return string $src Theme stylesheet striped location path.
|
|
*/
|
|
public static function remove_theme_versions( $src ) {
|
|
if ( static::get_security_option( 'styles_version' ) ) {
|
|
if ( strpos( $src, '?ver=' ) ) {
|
|
$src = remove_query_arg( 'ver', $src );
|
|
}
|
|
return $src;
|
|
}
|
|
return $src;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method remove_database_reporting_ok()
|
|
*
|
|
* Check if the database error reporting has been disabled.
|
|
*
|
|
* @used-by MainWP_Security::get_stats_security() Calculate total number of detected secutiry issues.
|
|
*
|
|
* @return bool true|false If the database error reporting has been disabled, return true, if not, return false.
|
|
*/
|
|
public static function remove_database_reporting_ok() {
|
|
|
|
/**
|
|
* Object, providing access to the WordPress database.
|
|
*
|
|
* @global $wpdb WordPress Database instance.
|
|
*/
|
|
global $wpdb;
|
|
|
|
return false === $wpdb->show_errors;
|
|
}
|
|
|
|
/**
|
|
* Method remove_php_reporting_ok()
|
|
*
|
|
* Check if the PHP error reporting has been disabled.
|
|
*
|
|
* @used-by MainWP_Security::get_stats_security() Calculate total number of detected secutiry issues.
|
|
*
|
|
* @return bool true|false If the PHP error reporting has been disabled, return true, if not, return false.
|
|
*/
|
|
public static function remove_php_reporting_ok() {
|
|
$is_ok = true;
|
|
$display_off = ini_get( 'display_errors' );
|
|
if ( ! empty( $display_off ) ) {
|
|
$display_off = strtolower( $display_off );
|
|
$is_ok = ( $is_ok || 'off' === $display_off );
|
|
}
|
|
$display_startup_off = ini_get( 'display_startup_errors' );
|
|
if ( ! empty( $display_startup_off ) ) {
|
|
$display_startup_off = strtolower( $display_startup_off );
|
|
$is_ok = ( $is_ok || 'off' === $display_startup_off );
|
|
}
|
|
return $is_ok;
|
|
}
|
|
|
|
/**
|
|
* Method get_stats_security()
|
|
*
|
|
* Calculate total number of detected secutiry issues.
|
|
*
|
|
* @uses MainWP_Security::remove_database_reporting_ok() Check if the database error reporting has been disabled.
|
|
* @uses MainWP_Security::remove_php_reporting_ok() Check if the PHP error reporting has been disabled.
|
|
*
|
|
* @return int $total_issues Total number of detected security issues.
|
|
*/
|
|
public static function get_stats_security() {
|
|
$total_issues = 0;
|
|
if ( ! static::remove_database_reporting_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
if ( ! static::remove_php_reporting_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
if ( ! static::wpcore_updated_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
if ( ! static::phpversion_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
if ( ! static::sslprotocol_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
if ( ! static::debug_disabled_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
if ( ! static::outdated_plugins_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
if ( ! static::inactive_plugins_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
if ( ! static::outdated_themes_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
if ( ! static::inactive_themes_ok() ) {
|
|
++$total_issues;
|
|
}
|
|
|
|
return $total_issues;
|
|
}
|
|
|
|
/**
|
|
* Method get_security_option()
|
|
*
|
|
* Get security check settings.
|
|
*
|
|
* @param string $option Security check option.
|
|
*
|
|
* @return bool Security settings.
|
|
*
|
|
* @uses \MainWP\Child\MainWP_Helper::update_option()
|
|
*/
|
|
public static function get_security_option( $option ) {
|
|
$security = get_option( 'mainwp_security' );
|
|
if ( false === $security ) {
|
|
// to fix issue of cached loading variable.
|
|
MainWP_Helper::update_option( 'mainwp_security', '', 'yes' );
|
|
}
|
|
return is_array( $security ) && isset( $security[ $option ] ) && ( true === $security[ $option ] );
|
|
}
|
|
|
|
|
|
/**
|
|
* Method update_security_option()
|
|
*
|
|
* Update the security issues feature settings.
|
|
*
|
|
* @param string $key Security option key.
|
|
* @param string $value Security option value.
|
|
*/
|
|
public static function update_security_option( $key, $value ) {
|
|
$security = get_option( 'mainwp_security' );
|
|
if ( ! empty( $key ) ) {
|
|
$security[ $key ] = $value;
|
|
}
|
|
MainWP_Helper::update_option( 'mainwp_security', $security, 'yes' );
|
|
}
|
|
|
|
/**
|
|
* Method wpcore_updated_ok()
|
|
*
|
|
* Check WP core updated.
|
|
*/
|
|
public static function wpcore_updated_ok() {
|
|
include_once ABSPATH . '/wp-admin/includes/update.php'; // NOSONAR -- WP compatible.
|
|
$ok = true;
|
|
$core_updates = get_core_updates();
|
|
if ( is_array( $core_updates ) ) {
|
|
foreach ( $core_updates as $update ) {
|
|
if ( 'upgrade' === $update->response ) {
|
|
$ok = false;
|
|
}
|
|
}
|
|
}
|
|
return $ok;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method phpversion_ok()
|
|
*
|
|
* Check PHP version matches the WP requirement.
|
|
*/
|
|
public static function phpversion_ok() {
|
|
require_once ABSPATH . WPINC . '/version.php'; // NOSONAR - WP compatible.
|
|
$required_php_version = '8.0';
|
|
return version_compare( phpversion(), $required_php_version, '>=' );
|
|
}
|
|
|
|
/**
|
|
* Method sslprotocol_ok()
|
|
*
|
|
* Check SSL protocol is in place.
|
|
*/
|
|
public static function sslprotocol_ok() {
|
|
return is_ssl();
|
|
}
|
|
|
|
|
|
/**
|
|
* Method debug_disabled_ok()
|
|
*
|
|
* Check WP Config and check if debugging is disabled.
|
|
*/
|
|
public static function debug_disabled_ok() {
|
|
return ! defined( 'WP_DEBUG' ) || ! WP_DEBUG;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method outdated_plugins_ok()
|
|
*
|
|
* Check WP Config and check if debugging is disabled.
|
|
*/
|
|
public static function outdated_plugins_ok() {
|
|
return MainWP_Child_Stats::get_instance()->found_plugins_updates() ? false : true;
|
|
}
|
|
|
|
/**
|
|
* Method inactive_plugins_ok()
|
|
*
|
|
* Check WP Config and check if debugging is disabled.
|
|
*/
|
|
public static function inactive_plugins_ok() {
|
|
return MainWP_Child_Stats::get_instance()->found_inactive_plugins() ? false : true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method outdated_themes_ok()
|
|
*
|
|
* Check WP Config and check if debugging is disabled.
|
|
*/
|
|
public static function outdated_themes_ok() {
|
|
return MainWP_Child_Stats::get_instance()->found_themes_updates() ? false : true;
|
|
}
|
|
|
|
/**
|
|
* Method inactive_themes_ok()
|
|
*
|
|
* Check WP Config and check if debugging is disabled.
|
|
*/
|
|
public static function inactive_themes_ok() {
|
|
return MainWP_Child_Stats::get_instance()->is_good_themes() ? true : false;
|
|
}
|
|
}
|