PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.3.24
CloudSecure WP Security v1.3.24
1.4.10 1.4.9 trunk 0.9.0 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.19 1.3.2 1.3.20 1.3.21 1.3.22 1.3.23 1.3.24 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8
cloudsecure-wp-security / modules / disable-login.php
cloudsecure-wp-security / modules Last commit date
admin 5 months ago cli 8 months ago lib 11 months ago captcha.php 2 years ago cloudsecure-wp.php 5 months ago common.php 1 year ago config.php 2 years ago disable-access-system-file.php 1 year ago disable-author-query.php 2 years ago disable-login.php 1 year ago disable-restapi.php 7 months ago disable-xmlrpc.php 1 year ago htaccess.php 5 months ago login-log.php 1 year ago login-notification.php 1 year ago rename-login-page.php 1 year ago restrict-admin-page.php 10 months ago server-error-notification.php 1 year ago two-factor-authentication.php 6 months ago unify-messages.php 2 years ago update-notice.php 7 months ago waf-engine.php 7 months ago waf.php 1 year ago
disable-login.php
337 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 class CloudSecureWP_Disable_Login extends CloudSecureWP_Common {
8 private const KEY_FEATURE = 'disable_login';
9 private const KEY_INTERVAL = self::KEY_FEATURE . '_interval';
10 private const KEY_LIMIT = self::KEY_FEATURE . '_limit';
11 private const KEY_DURATION = self::KEY_FEATURE . '_duration';
12 private const INTERVAL_VALUES = array( '5', '15', '30' ); // 秒 .
13 private const LIMIT_VALUES = array( '5', '15', '30' ); // 回 .
14 private const DURATION_VALUES = array( '60', '180', '300', '600', '3600' ); // 秒 .
15 private const LOGIN_EXPIRED_HOUR = 24;
16 private const TABLE_NAME = 'cloudsecurewp_login';
17 private const ERROR_CODE = 'cloudsecurewp_disable_login_error';
18 private $login_status = self::LOGIN_STATUS_FAILED;
19 private $config;
20
21 function __construct( array $info, CloudSecureWP_Config $config ) {
22 parent::__construct( $info );
23 $this->config = $config;
24 }
25
26 /**
27 * 機能毎のKEY取得
28 *
29 * @return string
30 */
31 public function get_feature_key(): string {
32 return self::KEY_FEATURE;
33 }
34
35 /**
36 * 有効無効判定
37 *
38 * @return bool
39 */
40 public function is_enabled(): bool {
41 return $this->config->get( $this->get_feature_key() ) === 't' ? true : false;
42 }
43
44 /**
45 * 初期設定値取得
46 *
47 * @return array
48 */
49 public function get_default(): array {
50 $ret = array(
51 self::KEY_FEATURE => $this->check_environment() ? 't' : 'f',
52 self::KEY_INTERVAL => self::INTERVAL_VALUES[0],
53 self::KEY_LIMIT => self::LIMIT_VALUES[0],
54 self::KEY_DURATION => self::DURATION_VALUES[0],
55 );
56 return $ret;
57 }
58
59 /**
60 * 設定値取得
61 */
62 public function get_settings(): array {
63 $settings = array();
64 $default = $this->get_default();
65
66 foreach ( $default as $key => $val ) {
67 $settings[ $key ] = $this->config->get( $key );
68 }
69
70 return $settings;
71 }
72
73 /**
74 * 設定値保存
75 *
76 * @param array $settings
77 * @return void
78 */
79 public function save_settings( $settings ): void {
80 $default = $this->get_default();
81
82 foreach ( $default as $key => $val ) {
83 $this->config->set( $key, $settings[ $key ] ?? '' );
84 }
85 $this->config->save();
86 }
87
88 /**
89 * 設定定義値取得
90 *
91 * @return array
92 */
93 public function get_constant_settings(): array {
94 $ret = array(
95 self::KEY_INTERVAL => self::INTERVAL_VALUES,
96 self::KEY_LIMIT => self::LIMIT_VALUES,
97 self::KEY_DURATION => self::DURATION_VALUES,
98 );
99 return $ret;
100 }
101
102 /**
103 * ステータス定義値取得
104 *
105 * @return array
106 */
107 public function get_constant_status(): array {
108 $ret = array(
109 self::LOGIN_STATUS_SUCCESS => 'ログイン成功',
110 self::LOGIN_STATUS_FAILED => 'ログイン失敗',
111 self::LOGIN_STATUS_DISABLED => '無効化',
112 );
113 return $ret;
114 }
115
116 /**
117 * ログイン成功ステータス取得
118 */
119 public function get_status_success(): int {
120 return self::LOGIN_STATUS_SUCCESS;
121 }
122
123 /**
124 * ログインステータス取得
125 */
126 public function get_login_status(): int {
127 return $this->login_status;
128 }
129
130 public function set_login_status( int $status ): void {
131 $this->login_status = $status;
132 }
133
134 /**
135 * テーブル名取得
136 *
137 * @return string
138 */
139 public function get_table_name(): string {
140 global $wpdb;
141 return $wpdb->prefix . self::TABLE_NAME;
142 }
143
144 /**
145 * テーブル作成
146 */
147 public function create_table(): void {
148 global $wpdb;
149 $table_name = $this->get_table_name();
150 $table = $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
151
152 if ( is_null( $table ) ) {
153 $charset_collate = $wpdb->get_charset_collate();
154
155 $sql = "CREATE TABLE {$table_name} (
156 ip VARCHAR( 39 ) NOT NULL DEFAULT '',
157 status INT NOT NULL DEFAULT 0,
158 failed_count INT NOT NULL DEFAULT 0,
159 login_at DATETIME,
160 UNIQUE KEY index_ip ( ip )
161 ) {$charset_collate}";
162
163 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
164 dbDelta( $sql );
165 }
166 }
167
168 /**
169 * 期限切れログイン�
170 報削除
171 *
172 * @return void
173 */
174 public function remove_expired_login(): void {
175 global $wpdb;
176
177 $table_name = $this->get_table_name();
178 $expired_hour = self::LOGIN_EXPIRED_HOUR;
179 $sql = "DELETE FROM {$table_name} WHERE login_at < SYSDATE() - INTERVAL {$expired_hour} HOUR;";
180
181 $wpdb->query( $sql );
182 }
183
184 /**
185 * ipアドレスでログイン�
186 報取得
187 *
188 * @param string $ip
189 * @return array $row
190 */
191 public function get_row_by_ip( string $ip ): array {
192 global $wpdb;
193
194 $sql = $wpdb->prepare( "SELECT * from {$wpdb->prefix}cloudsecurewp_login WHERE ip = %s", $ip );
195 $row = $wpdb->get_row( $sql, ARRAY_A );
196
197 return $row ?? array();
198 }
199
200 /**
201 * ログインステータスが成功のレコード�
202 �件取得
203 *
204 * @return array $row
205 */
206 public function get_rows_status_success(): array {
207 global $wpdb;
208
209 $sql = $wpdb->prepare( "SELECT * from {$wpdb->prefix}cloudsecurewp_login WHERE status = %d", $this->get_status_success() );
210 $row = $wpdb->get_results( $sql, ARRAY_A );
211
212 return $row ?? array();
213 }
214
215 /**
216 * wp_login_failed
217 *
218 * @param string $user_name
219 * @return void
220 */
221 public function wp_login_failed( $user_name ): void {
222 global $wpdb;
223
224 $this->set_login_status( self::LOGIN_STATUS_FAILED );
225
226 $ip = $this->get_client_ip();
227 $now_datetime = current_time( 'mysql' );
228 $now_time = strtotime( $now_datetime );
229 $data = array(
230 'ip' => $ip,
231 'status' => self::LOGIN_STATUS_FAILED,
232 'failed_count' => 1,
233 'login_at' => $now_datetime,
234 );
235
236 $wpdb->query( 'START TRANSACTION' );
237 $this->remove_expired_login();
238 $row = $this->get_row_by_ip( $ip );
239
240 if ( empty( $row ) ) {
241 $wpdb->insert( $this->get_table_name(), $data );
242
243 } else {
244 $row['status'] = (int) $row['status'];
245 $row['failed_count'] = (int) $row['failed_count'];
246
247 if ( self::LOGIN_STATUS_FAILED === $row['status'] ) {
248 $now_failed_count = $row['failed_count'] + 1;
249 $interval_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_INTERVAL );
250
251 if ( (int) $this->config->get( self::KEY_LIMIT ) <= $now_failed_count ) {
252 $data['status'] = self::LOGIN_STATUS_DISABLED;
253 $data['failed_count'] = $now_failed_count;
254
255 } elseif ( $now_time <= $interval_time ) {
256 $data['failed_count'] = $now_failed_count;
257 $data['login_at'] = $row['login_at'];
258 }
259 } elseif ( self::LOGIN_STATUS_DISABLED === $row['status'] ) {
260 $this->set_login_status( $row['status'] );
261 $duration_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_DURATION );
262
263 if ( $now_time <= $duration_time ) {
264 $data['status'] = $row['status'];
265 $data['login_at'] = $row['login_at'];
266 }
267 }
268 $wpdb->update( $this->get_table_name(), $data, array( 'ip' => $ip ) );
269
270 }
271 $wpdb->query( 'COMMIT' );
272 }
273
274 /**
275 * エラーコード追加
276 */
277 public function shake_error_codes( $error_codes ) {
278 array_push( $error_codes, self::ERROR_CODE );
279 return $error_codes;
280 }
281
282 /**
283 * 認証
284 *
285 * @param $user
286 * @param string $user_name
287 * @param string $password
288 */
289 public function authenticate( $user, $user_name, $password ) {
290 if ( $this->is_disable() ) {
291 return new WP_Error( self::ERROR_CODE, 'ログイン失敗回数が上限に達したためログインが無効化されました。' );
292 }
293 return $user;
294 }
295
296 /**
297 * ログイン無効判定
298 *
299 * @return bool
300 */
301 public function is_disable(): bool {
302 $ip = $this->get_client_ip();
303 $row = $this->get_row_by_ip( $ip );
304
305 if ( ! empty( $row ) && self::LOGIN_STATUS_DISABLED === (int) $row['status'] ) {
306 $now_time = strtotime( current_time( 'mysql' ) );
307 $duration_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_DURATION );
308
309 if ( $now_time <= $duration_time ) {
310 return true;
311 }
312 }
313
314 return false;
315 }
316
317 /**
318 * 有効化
319 *
320 * @return void
321 */
322 public function activate(): void {
323 $this->save_settings( $this->get_default() );
324 $this->create_table();
325 }
326
327 /**
328 * 無効化
329 *
330 * @return void
331 */
332 public function deactivate(): void {
333 $this->config->set( $this->get_feature_key(), 'f' );
334 $this->config->save();
335 }
336 }
337