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-session-protection.php +48 -3 6.2.4 → 6.3.0 View file →
@@ -146,16 +146,49 @@
146 146 $this->update_last_activity();
147 147 }
148 148
149 149 /**
150 + * Get transient key for server-side session last activity.
151 + *
152 + * @param int|null $user_id User ID.
153 + * @return string|null
154 + */
155 + private function get_session_activity_key( $user_id = null ): ?string {
156 + $user_id = $user_id ?? get_current_user_id();
157 + if ( ! $user_id ) {
158 + return null;
159 + }
160 +
161 + $token = wp_get_session_token();
162 + if ( ! $token ) {
163 + return 'wpdef_last_act_' . $user_id;
164 + }
165 +
166 + return 'wpdef_last_act_' . $user_id . '_' . substr( md5( $token ), 0, 16 );
167 + }
168 +
169 + /**
150 170 * Retrieves the last activity timestamp.
151 171 *
152 172 * @return int|null Last activity timestamp or null if not set.
153 173 */
154 174 private function get_last_activity() {
155 - // Check for client-side cookie first to avoid unnecessary database queries.
175 + // First check server-side session state if available to prevent client tampering.
176 + $key = $this->get_session_activity_key();
177 + if ( $key ) {
178 + $server_activity = get_transient( $key );
179 + if ( is_numeric( $server_activity ) && (int) $server_activity > 0 ) {
180 + return (int) $server_activity;
181 + }
182 + }
183 +
184 + // Fallback to client-side cookie if server transient is missing.
156 185 if ( isset( $_COOKIE['wpdef_last_activity'] ) && is_numeric( $_COOKIE['wpdef_last_activity'] ) ) {
157 - return (int) $_COOKIE['wpdef_last_activity'];
186 + $timestamp = (int) $_COOKIE['wpdef_last_activity'];
187 + $now = time();
188 +
189 + // Clamp future timestamps to current server time to prevent session timeout bypass.
190 + return min( $timestamp, $now );
158 191 }
159 192
160 193 return null;
161 194 }
@@ -178,8 +211,14 @@
178 211 );
179 212 // Fires during session timeout.
180 213 do_action( 'wpdef_session_timeout', $user_id );
181 214 }
215 +
216 + $key = $this->get_session_activity_key( $user_id );
217 + if ( $key ) {
218 + delete_transient( $key );
219 + }
220 +
182 221 // Get current session token.
183 222 $current_session_token = wp_get_session_token();
184 223 if ( $current_session_token ) {
185 224 // Get session manager for the user.
@@ -300,9 +339,15 @@
300 339 *
301 340 * @return void
302 341 */
303 342 public function update_last_activity() {
304 - $current_time = time();
343 + $current_time = time();
344 +
345 + $key = $this->get_session_activity_key();
346 + if ( $key ) {
347 + set_transient( $key, $current_time, DAY_IN_SECONDS );
348 + }
349 +
305 350 $last_activity = $this->get_last_activity();
306 351
307 352 // Only update the cookie if minutes have passed since the last update.
308 353 if ( ! is_null( $last_activity ) || ( $current_time - $last_activity > MINUTE_IN_SECONDS ) ) {