PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/component/class-firewall.php +55 -11 5.8.1 → 6.3.0 View file →
@@ -14,9 +14,9 @@
14 14 use WP_Defender\Model\Lockout_Ip;
15 15 use WP_Defender\Behavior\WPMUDEV;
16 16 use WP_Defender\Model\Lockout_Log;
17 17 use WP_Defender\Model\Onboard;
18 -use MaxMind\Db\Reader\InvalidDatabaseException;
18 +use WP_DEFENDER_VENDOR\MaxMind\Db\Reader\InvalidDatabaseException;
19 19 use WP_Defender\Model\Setting\Firewall as Model_Firewall;
20 20 use WP_Defender\Component\Trusted_Proxy_Preset\Cloudflare_Proxy;
21 21 use WP_Defender\Component\Trusted_Proxy_Preset\Trusted_Proxy_Preset;
22 22 use WP_Defender\Controller\Firewall as Firewall_Controller;
@@ -63,18 +63,50 @@
63 63 private function is_commencing_staff_access( $access ): bool {
64 64 $action = defender_get_data_from_request( 'action', 'g' );
65 65 $wdpunkey = defender_get_data_from_request( 'wdpunkey', 'p' );
66 66
67 - return wp_doing_ajax() && 'wdpunauth' === $action && hash_equals( $wdpunkey, $access['key'] );
67 + return wp_doing_ajax() && 'wdpunauth' === $action && isset( $access['key'] ) && hash_equals( $wdpunkey, $access['key'] );
68 68 }
69 69
70 70 /**
71 71 * Check is the access from authenticated staff.
72 72 *
73 - * @return bool
73 + * Validates the `wpmudev_is_staff` cookie token by verifying:
74 + * - Token version and structure (v1.<payload>.<signature>)
75 + * - HMAC-SHA256 signature against site salt (`wpmudev_remote_access`)
76 + * - Token expiration timestamp against current time
77 + * - Audience (`aud`) against current site URL (`home_url('/')`)
78 + * - Subject (`sub`) against currently authenticated user ID
79 + *
80 + * @return bool True if staff access token is valid and unexpired, false otherwise.
74 81 */
75 82 private function is_authenticated_staff_access(): bool {
76 - return '1' === defender_get_data_from_request( 'wpmudev_is_staff', 'c' );
83 + $cookie = defender_get_data_from_request( 'wpmudev_is_staff', 'c' );
84 + if ( ! is_string( $cookie ) ) {
85 + return false;
86 + }
87 +
88 + $token = explode( '.', $cookie, 3 );
89 + if ( 3 !== count( $token ) || 'v1' !== $token[0] ) {
90 + return false;
91 + }
92 +
93 + $signature = hash_hmac( 'sha256', $token[1], wp_salt( 'wpmudev_remote_access' ) );
94 + if ( ! hash_equals( $signature, $token[2] ) ) {
95 + return false;
96 + }
97 + // Improve flow to avoid bypassing staff access authentication via an unsigned cookie. Use legitim payload.
98 + $payload = base64_decode( strtr( $token[1], '-_', '+/' ) . str_repeat( '=', ( 4 - strlen( $token[1] ) % 4 ) % 4 ), true );// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
99 + $payload = is_string( $payload ) ? json_decode( $payload, true ) : null;
100 +
101 + return is_array( $payload ) &&
102 + isset( $payload['aud'], $payload['exp'], $payload['sub'] ) &&
103 + is_string( $payload['aud'] ) &&
104 + is_numeric( $payload['exp'] ) &&
105 + is_numeric( $payload['sub'] ) &&
106 + (int) $payload['exp'] > time() &&
107 + hash_equals( home_url( '/' ), $payload['aud'] ) &&
108 + get_current_user_id() === (int) $payload['sub'];
77 109 }
78 110
79 111 /**
80 112 * Check if the access is from our staff access.
@@ -85,15 +117,24 @@
85 117 if ( defined( 'WPMUDEV_DISABLE_REMOTE_ACCESS' ) && true === constant( 'WPMUDEV_DISABLE_REMOTE_ACCESS' ) ) {
86 118 return false;
87 119 }
88 120
89 - $wpmu_dev = new WPMUDEV();
90 - $is_remote_access = $wpmu_dev->get_apikey() &&
121 + $wpmu_dev = new WPMUDEV();
122 +
123 + // Remote staff access needs Dashboard mode.
124 + if ( 'dashboard' !== $wpmu_dev->resolve_connection_mode() ) {
125 + return false;
126 + }
127 +
128 + $is_remote_access = is_object( WPMUDEV_Dashboard::$api ) &&
91 129 true === WPMUDEV_Dashboard::$api->remote_access_details( 'enabled' );
92 130
93 131 if ( $is_remote_access ) {
94 - $access = $wpmu_dev->get_remote_access();
95 - if ( $this->is_authenticated_staff_access() || $this->is_commencing_staff_access( $access ) ) {
132 + $access = $wpmu_dev->get_remote_access();
133 + $is_authenticated_staff_access = isset( $access['userid'] ) &&
134 + get_current_user_id() === (int) $access['userid'] &&
135 + $this->is_authenticated_staff_access();
136 + if ( $is_authenticated_staff_access || $this->is_commencing_staff_access( $access ) ) {
96 137 $this->log( $access, Firewall_Controller::FIREWALL_LOG );
97 138
98 139 return true;
99 140 }
@@ -115,9 +156,10 @@
115 156 }
116 157 $time_string = '-' . $storage_days . ' days';
117 158 $timestamp = $this->local_to_utc( $time_string );
118 159 // Since v5.7.0.
119 - $delete_count = (int) apply_filters( 'wpdef_firewall_limit_deleted_logs', 50 );
160 + $delete_count = apply_filters( 'wpdef_firewall_limit_deleted_logs', 50 );
161 + $delete_count = is_int( $delete_count ) ? $delete_count : (int) $delete_count;
120 162 Lockout_Log::remove_logs( $timestamp, $delete_count );
121 163 }
122 164
123 165 /**
@@ -271,9 +313,10 @@
271 313 * @return int
272 314 * @since 3.7.0 Get the limit of Lockout records.
273 315 */
274 316 public function get_lockout_record_limit() {
275 - return (int) apply_filters( 'wd_lockout_record_limit', 10000 );
317 + $limit = apply_filters( 'wd_lockout_record_limit', 10000 );
318 + return is_int( $limit ) ? $limit : (int) $limit;
276 319 }
277 320
278 321 /**
279 322 * Cron for deleting unwanted lockout records.
@@ -573,9 +616,10 @@
573 616 * @param bool $enable True to enable whitelist server public IP, false otherwise.
574 617 *
575 618 * @since 5.0.2
576 619 */
577 - return (bool) apply_filters( 'wpdef_firewall_whitelist_server_public_ip_enabled', true );
620 + $enabled = apply_filters( 'wpdef_firewall_whitelist_server_public_ip_enabled', true );
621 + return is_bool( $enabled ) ? $enabled : (bool) $enabled;
578 622 }
579 623
580 624 /**
581 625 * Set whitelist server public IP.