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
defender-security / src / component / class-firewall-logs.php

class-firewall-logs.php in Defender Security – Malware Scanner, Login Security & Firewall 6.3.0, at src/component/class-firewall-logs.php

182 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The firewall logs class.
4 *
5 * @package WP_Defender\Component
6 */
7
8 namespace WP_Defender\Component;
9
10 use WP_Defender\Component;
11 use WP_Defender\Model\Lockout_Log;
12 use WP_Defender\Model\Spam_Comment;
13
14 /**
15 * Class Firewall_Logs
16 */
17 class Firewall_Logs extends Component {
18
19 /**
20 * Fetch compact Firewall logs. Combination of conditions:
21 * 1. Logs for the specified period.
22 * 2. '404_error'-logs with the same IP, the number of which is not less than 20.
23 * 3. Exclude UA-logs that match entries in the blocklist. Only REASON_BAD_POST UA-logs with the same IP.
24 *
25 * @param int $from Fetch Logs from this time to current time.
26 *
27 * @return array
28 */
29 public function get_compact_logs( int $from ): array {
30 global $wpdb;
31
32 $table = $wpdb->base_prefix . ( new Lockout_Log() )->get_table();
33 $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
34 $wpdb->prepare(
35 "SELECT IP, type, tried, COUNT(*) AS frequency FROM {$table}" . // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
36 " WHERE `date` >= %s AND (type IN ('auth_fail', '404_error')" .
37 " OR (type = 'ua_lockout' AND tried = %s))" .
38 ' GROUP BY IP, `type`',
39 $from,
40 \WP_Defender\Component\User_Agent::REASON_BAD_POST
41 ),
42 ARRAY_A
43 );
44
45 $logs = array();
46 if ( is_array( $results ) ) {
47 foreach ( $results as $row ) {
48 $frequency = (int) $row['frequency'];
49
50 if ( '404_error' === $row['type'] ) {
51 $frequency = intdiv( $frequency, 20 );
52
53 if ( $frequency < 1 ) {
54 continue;
55 }
56 }
57
58 $type = '';
59 switch ( $row['type'] ) {
60 case 'auth_fail':
61 $type = 'login';
62 break;
63 case '404_error':
64 $type = 'not_found';
65 break;
66 case 'ua_lockout':
67 $type = 'user_agent';
68 break;
69 default:
70 continue 2;
71 }
72
73 $ip = $row['IP'];
74 if ( ! isset( $logs[ $ip ] ) ) {
75 $logs[ $ip ] = array( 'ip' => $ip );
76 }
77
78 $logs[ $ip ]['reason'][ $type ] = $frequency;
79 }
80 }
81
82 $spam_comments_ip = Spam_Comment::get_spam_comments_ip();
83 if ( array() !== $spam_comments_ip ) {
84 // Add spam comments IP to the compact log.
85 $this->log( $spam_comments_ip, 'spam-comment.log' );
86
87 foreach ( $spam_comments_ip as $ip => $count ) {
88 if ( ! isset( $logs[ $ip ] ) ) {
89 $logs[ $ip ] = array( 'ip' => $ip );
90 }
91
92 $logs[ $ip ]['reason']['spam_comment'] = $count;
93 }
94 }
95
96 return array_values( $logs );
97 }
98
99 /**
100 * Get spam comment logs automatically marked by the Akismet plugin.
101 *
102 * @return array
103 */
104 public function get_akismet_auto_spam_comment_logs(): array {
105 $logs = array();
106 // Retrieve the current list of blocked IPs from the site transient.
107 $ips = get_site_transient( \WP_Defender\Controller\Firewall_Logs::AKISMET_BLOCKED_IPS );
108 // Ensure the retrieved data is an array; if not, initialize it as an empty array.
109 if ( is_array( $ips ) && array() !== $ips ) {
110 $this->log( $ips, 'spam-comment.log' );
111
112 foreach ( $ips as $ip => $count ) {
113 if ( ! isset( $logs[ $ip ] ) ) {
114 $logs[ $ip ] = array( 'ip' => $ip );
115 }
116
117 $logs[ $ip ]['reason']['spam_comment'] = $count;
118 }
119 }
120
121 delete_site_transient( \WP_Defender\Controller\Firewall_Logs::AKISMET_BLOCKED_IPS );
122
123 return array_values( $logs );
124 }
125
126 /**
127 * Fetch 404 Intelligence Firewall logs.
128 *
129 * @param int $from Fetch Logs from this time to current time.
130 *
131 * @return array
132 */
133 public function get_404_intelligence_logs( int $from ): array {
134 global $wpdb;
135
136 $table = $wpdb->base_prefix . ( new Lockout_Log() )->get_table();
137 $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
138 $wpdb->prepare(
139 "SELECT IP, type, COUNT(*) AS frequency FROM {$table}" . // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
140 ' WHERE `date` >= %s AND type IN (%s, %s, %s)' .
141 ' GROUP BY IP, `type`',
142 $from,
143 \WP_Defender\Model\Lockout_Log::ERROR_404_XSS,
144 \WP_Defender\Model\Lockout_Log::ERROR_404_NON_EXISTENT_PLUGIN,
145 \WP_Defender\Model\Lockout_Log::ERROR_404_NON_EXISTENT_THEME
146 ),
147 ARRAY_A
148 );
149
150 $logs = array();
151 if ( is_array( $results ) ) {
152 foreach ( $results as $row ) {
153 $frequency = (int) $row['frequency'];
154
155 $type = '';
156 switch ( $row['type'] ) {
157 case \WP_Defender\Model\Lockout_Log::ERROR_404_XSS:
158 $type = 'not_found_xss';
159 break;
160 case \WP_Defender\Model\Lockout_Log::ERROR_404_NON_EXISTENT_PLUGIN:
161 $type = 'not_found_plugin';
162 break;
163 case \WP_Defender\Model\Lockout_Log::ERROR_404_NON_EXISTENT_THEME:
164 $type = 'not_found_theme';
165 break;
166 default:
167 continue 2;
168 }
169
170 $ip = $row['IP'];
171 if ( ! isset( $logs[ $ip ] ) ) {
172 $logs[ $ip ] = array( 'ip' => $ip );
173 }
174
175 $logs[ $ip ]['reason'][ $type ] = $frequency;
176 }
177 }
178
179 return array_values( $logs );
180 }
181 }
182