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-fake-bot-detection.php +19 -113 5.9.0 → 6.3.0 View file →
@@ -7,13 +7,15 @@
7 7
8 8 namespace WP_Defender\Component;
9 9
10 10 use WP_Defender\Component;
11 +use WP_Defender\Traits\Country;
12 +use WP_Defender\Model\Lockout_Ip;
13 +use WP_Defender\Model\Lockout_Log;
11 14 use WP_Defender\Controller\Firewall;
12 -use WP_Defender\Model\Lockout_Log;
13 15 use WP_Defender\Model\Setting\User_Agent_Lockout;
14 -use WP_Defender\Model\Lockout_Ip;
15 -use WP_Defender\Traits\Country;
16 +use WP_Defender\Component\Known_Bots\Bots\Facebook_Bot;
17 +use WP_Defender\Model\Notification\Firewall_Notification;
16 18
17 19 /**
18 20 * Class Fake_Bot_Detection
19 21 *
@@ -77,13 +79,9 @@
77 79 * API endpoints to query for IP info.
78 80 *
79 81 * @var string[]
80 82 */
81 - public const IP_INFO_SERVICES = array(
82 - 'https://ipinfo.io/%s/json',
83 - 'https://ipwho.is/%s',
84 - 'http://ip-api.com/json/%s',
85 - );
83 + public const IP_INFO_SERVICES = Facebook_Bot::IP_INFO_SERVICES;
86 84
87 85 /**
88 86 * Prefix for site transient cache keys.
89 87 *
@@ -88,15 +86,15 @@
88 86 * Prefix for site transient cache keys.
89 87 *
90 88 * @var string
91 89 */
92 - public const FB_CACHE_KEY_PREFIX = 'wpdef_ip_is_fb_';
90 + public const FB_CACHE_KEY_PREFIX = Facebook_Bot::FB_CACHE_KEY_PREFIX;
93 91
94 92 /**
95 93 * Cache lifetimes.
96 94 */
97 - public const FB_CACHE_TTL_CONFIRMED = WEEK_IN_SECONDS;
98 - public const FB_CACHE_TTL_UNCONFIRMED = HOUR_IN_SECONDS;
95 + public const FB_CACHE_TTL_CONFIRMED = Facebook_Bot::FB_CACHE_TTL_CONFIRMED;
96 + public const FB_CACHE_TTL_UNCONFIRMED = Facebook_Bot::FB_CACHE_TTL_UNCONFIRMED;
99 97
100 98 /**
101 99 * Fake_Bot_Detection constructor.
102 100 *
@@ -136,12 +134,8 @@
136 134 if ( array() === $ips || '' === $agent ) {
137 135 return;
138 136 }
139 137
140 - if ( false !== stripos( $agent, 'facebook' ) && false !== stripos( $agent, 'twitter' ) ) {
141 - return;
142 - }
143 -
144 138 foreach ( $this->crawlers as $name => $data ) {
145 139 // 1. User-Agent check.
146 140 if ( ! $this->match_user_agent( $agent, $data['user_agents'] ?? array() ) ) {
147 141 continue;
@@ -159,15 +153,10 @@
159 153 return;
160 154 }
161 155
162 156 // Facebook specific IP verification.
163 - if ( 'facebook' === strtolower( $name ) ) {
164 - if ( $this->is_facebook_ip( $ip ) ) {
165 - return; // Confirmed legit Facebook bot.
166 - }
167 -
168 - $this->block_ip( $ip, $agent, $name );
169 - return;
157 + if ( 'facebook' === strtolower( $name ) && $this->is_facebook_ip( $ip ) ) {
158 + return; // Confirmed legit Facebook bot.
170 159 }
171 160
172 161 // 3. Reverse DNS lookup.
173 162 $hostname = gethostbyaddr( $ip );
@@ -188,9 +177,11 @@
188 177 return; // Verified by forward + reverse DNS.
189 178 }
190 179 }
191 180
192 - $this->block_ip( $ip, $agent, $name );
181 + if ( isset( $ip ) ) {
182 + $this->block_ip( $ip, $agent, $name );
183 + }
193 184 return; // UA matched, but DNS validation failed.
194 185 }
195 186 }
196 187
@@ -299,22 +290,10 @@
299 290 * @param string $scenario The scenario under which the event is logged.
300 291 * @param string $bot_name The name of the bot being impersonated.
301 292 */
302 293 public function log_event( $ip, $scenario, $bot_name ) {
303 - $model = new Lockout_Log();
304 - $model->ip = $ip;
305 - $user_agent = defender_get_data_from_request( 'HTTP_USER_AGENT', 's' );
306 - $model->user_agent = isset( $user_agent ) ? User_Agent::fast_cleaning( $user_agent ) : null;
307 - $model->date = time();
308 - $model->tried = $user_agent;
309 - $model->blog_id = get_current_blog_id();
294 + $model = Lockout_Log::create( $ip );
310 295
311 - $ip_to_country = $this->ip_to_country( $ip );
312 -
313 - if ( isset( $ip_to_country['iso'] ) ) {
314 - $model->country_iso_code = $ip_to_country['iso'];
315 - }
316 -
317 296 switch ( $scenario ) {
318 297 case self::SCENARIO_FAKE_BOT:
319 298 default:
320 299 $model->type = Lockout_Log::LOCKOUT_FAKE_BOT;
@@ -325,8 +304,10 @@
325 304 );
326 305 break;
327 306 }
328 307 $model->save();
308 + // Notify directly because the 'defender_notify' hook isn't registered yet at firewall-time.
309 + wd_di()->get( Firewall_Notification::class )->notify_lockout( $model );
329 310 }
330 311
331 312 /**
332 313 * Creates a lockout for a blocked IP.
@@ -347,63 +328,9 @@
347 328 * @param string $ip IPv4 or IPv6 address.
348 329 * @return bool True if owned by Facebook, false otherwise.
349 330 */
350 331 public function is_facebook_ip( string $ip ): bool {
351 - if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
352 - return false;
353 - }
354 -
355 - $cache_key = self::FB_CACHE_KEY_PREFIX . md5( $ip );
356 -
357 - $cached = get_site_transient( $cache_key );
358 - if ( false !== $cached ) {
359 - return (bool) $cached;
360 - }
361 -
362 - $is_fb = false;
363 -
364 - // Fetch from APIs.
365 - foreach ( self::IP_INFO_SERVICES as $endpoint ) {
366 - $url = sprintf( $endpoint, $ip );
367 -
368 - $response = wp_remote_get(
369 - $url,
370 - array(
371 - 'timeout' => 3,
372 - 'headers' => array( 'Accept' => 'application/json' ),
373 - )
374 - );
375 -
376 - if ( is_wp_error( $response ) ) {
377 - continue;
378 - }
379 -
380 - $body = wp_remote_retrieve_body( $response );
381 - $data = json_decode( $body, true );
382 -
383 - if ( ! is_array( $data ) ) {
384 - continue;
385 - }
386 -
387 - $org = $data['org'] ?? $data['connection']['org'] ?? null;
388 - $isp = $data['isp'] ?? $data['connection']['isp'] ?? null;
389 -
390 - if (
391 - preg_match( '/facebook|meta/i', $org ?? '' ) ||
392 - preg_match( '/facebook|meta/i', $isp ?? '' )
393 - ) {
394 - $is_fb = true;
395 - break;
396 - }
397 - }
398 -
399 - set_site_transient(
400 - $cache_key,
401 - $is_fb ? 1 : 0,
402 - $is_fb ? self::FB_CACHE_TTL_CONFIRMED : self::FB_CACHE_TTL_UNCONFIRMED
403 - );
404 -
405 - return $is_fb;
332 + return ( new Facebook_Bot() )->is_ip( $ip );
406 333 }
407 334
408 335 /**
409 336 * Clear all Facebook IP check transients.
@@ -408,28 +335,7 @@
408 335 /**
409 336 * Clear all Facebook IP check transients.
410 337 */
411 338 public function clear_fb_transients(): void {
412 - global $wpdb;
413 -
414 - $cache_key = self::FB_CACHE_KEY_PREFIX;
415 - $like_pattern = "_site_transient_{$cache_key}_%";
416 - $timeout_pattern = "_site_transient_timeout_{$cache_key}_%";
417 -
418 - if ( is_multisite() ) {
419 - $table = $wpdb->sitemeta;
420 - $key_column = 'meta_key';
421 - } else {
422 - $table = $wpdb->options;
423 - $key_column = 'option_name';
424 - }
425 -
426 - // Delete Facebook IP check transients.
427 - $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
428 - $wpdb->prepare(
429 - "DELETE FROM {$table} WHERE {$key_column} LIKE %s OR {$key_column} LIKE %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
430 - $like_pattern,
431 - $timeout_pattern
432 - )
433 - );
339 + ( new Facebook_Bot() )->clear_fb_transients();
434 340 }
435 341 }